美文网首页
第二节:反射学习

第二节:反射学习

作者: cf许我向你看 | 来源:发表于2017-06-29 11:23 被阅读15次

    1.反射机制:

    java运行期间动态的加载一些不确定的类的对象。大多数的情况下我们使用的是一个确定的类,通过在内存中的加载,再使用。
    反射机制提供的功能

    • 加载运行时才能确定的数据类型
    • 解析类的结构,获取其内部信息
    • 能够访问属性,调用方法,创建新的对象。

    1.1 动态加载类

    image.png

    通过以上的代码可以总结使用Reflection.需要如下几步:

    1. 获取目标对象的Class对象
    2. 调用Class对象内省方法获取目标对类成员信息
    3. 调用目标的成员属性

    1.2 解析类的结构

    1.2.1 定义一个Teacher的类

    public class Teacher {
    private String name;
        private  int age;
        private  static  int total;
        public Teacher(String name, int age) {
            this.name = name;
            this.age = age;
            total++;
        }
        public Teacher() {
           total++;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public static int getTotal() {
            return total;
        }
        public static void setTotal(int total) {
            Teacher.total = total;}
        @Override
        public String toString() {
            return "Teacher{" + "name='" + name + '\'' + ", age=" + age + '}';
        }
    }
    

    1.2.2 对Teacher进行解析

      public class RflectionTeacher {
        private  final  static  String TEACHER_CLASS="reflection.Teacher";
        public static void main(String[] args) {
            try {
                Class<?> clazz = Class.forName(TEACHER_CLASS);
                Field[] fields = clazz.getDeclaredFields();//获取该类中的属性属性成员
                Method[] methods = clazz.getDeclaredMethods();//获取该类的成员方法
                Constructor<?>[] constructors = clazz.getConstructors();//获取该类的所有的构造方法
                System.out.println("------打印成员属性-------");
                for(Field field:fields){
                    System.out.println("属性 :"+field);
                    System.out.println("名称 :"+field.getName());
                    System.out.println("修饰符 :"+ Modifier.toString(field.getModifiers()));
                    System.out.println("--------------------------------------------------");
                }
                for (Method method:methods){
                    System.out.println("方法 :"+method.toString());
                    System.out.println("方法名称 :"+method.getName());
                    System.out.println("方法修饰符 :"+Modifier.toString(method.getModifiers()));
                    System.out.println("------方法参数列表------");
                    Class<?>[] types = method.getParameterTypes();
                    System.out.println(types.length!=0?"有参数":"无参数:");
                    for (Class c:types){
                        System.out.println(c.getName()+"类型\t");
                    }
                    System.out.println("\n方法返回类 型 :"+method.getReturnType().getName());
                    System.out.println("=====================================");
                }
                System.out.println("***************打印构造方法 ***************");
                for(Constructor constructor:constructors){
                    System.out.println("构造方法 :"+constructor.toString());
                    System.out.println("构造方法名 :"+constructor.getName());
                    System.out.println("构造方法修饰符 :"+Modifier.toString(constructor.getModifiers()));
                    Class[] mClass=constructor.getParameterTypes();
                    System.out.print(mClass.length!=0?"有参数:":"无参数:");
                    for(Class c:mClass){
                        System.out.print(c.getName()+"类型\t");
                    }
                    System.out.println("\n=====================================");
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    

    1.2.3 输出结果

    ------打印成员属性-------
    属性 :private java.lang.String reflection.Teacher.name
    名称 :name
    修饰符 :private
    --------------------------------------------------
    属性 :private int reflection.Teacher.age
    名称 :age
    修饰符 :private
    --------------------------------------------------
    属性 :private static int reflection.Teacher.total
    名称 :total
    修饰符 :private static
    --------------------------------------------------
    方法 :public java.lang.String reflection.Teacher.toString()
    方法名称 :toString
    方法修饰符 :public
    ------方法参数列表------
    无参数:
    
    方法返回类 型 :java.lang.String
    =====================================
    方法 :public java.lang.String reflection.Teacher.getName()
    方法名称 :getName
    方法修饰符 :public
    ------方法参数列表------
    无参数:
    
    方法返回类 型 :java.lang.String
    =====================================
    方法 :public void reflection.Teacher.setName(java.lang.String)
    方法名称 :setName
    方法修饰符 :public
    ------方法参数列表------
    有参数
    java.lang.String类型  
    
    方法返回类 型 :void
    =====================================
    方法 :public static int reflection.Teacher.getTotal()
    方法名称 :getTotal
    方法修饰符 :public static
    ------方法参数列表------
    无参数:
    
    方法返回类 型 :int
    =====================================
    方法 :public int reflection.Teacher.getAge()
    方法名称 :getAge
    方法修饰符 :public
    ------方法参数列表------
    无参数:
    
    方法返回类 型 :int
    =====================================
    方法 :public void reflection.Teacher.setAge(int)
    方法名称 :setAge
    方法修饰符 :public
    ------方法参数列表------
    有参数
    int类型   
    
    方法返回类 型 :void
    =====================================
    方法 :public static void reflection.Teacher.setTotal(int)
    方法名称 :setTotal
    方法修饰符 :public static
    ------方法参数列表------
    有参数
    int类型   
    
    方法返回类 型 :void
    =====================================
    ***************打印构造方法 ***************
    构造方法 :public reflection.Teacher(java.lang.String,int)
    构造方法名 :reflection.Teacher
    构造方法修饰符 :public
    有参数:java.lang.String类型  int类型   
    =====================================
    构造方法 :public reflection.Teacher()
    构造方法名 :reflection.Teacher
    构造方法修饰符 :public
    无参数:
    =====================================
    

    1.3 访问类的属性和方法

    1.3.1 Student类

    public class Student {
    private String name;
        private static  int count=100;
        public Student() {
        }
        public Student(String name) {
            this.name = name;
        }
        public void setValue(String name){
            this.name = name;
        }
        public void showCount(){
            System.out.println("Student对象被实例化了"+count+"次");
        }
        public String toString(){
            return "Name:"+this.name+",调用次数:"+count;
        }
    }
    

    1.3.2 访问 name 属性的操作方法:

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
             //访问name属性的操作方法
            Student student = new Student("zhangsan");
            Class<? extends Student> claszz = student.getClass();
            Field field = claszz.getField("name");
            Object o = field.get(student);
            System.out.println("修改前 "+ field.getName()+" 的值 "+o);
            field.set(student,"李思");
            o=field.get(student);
            System.out.println("修改后:"+field.getName()+"的值:"+o);
        }
    

    1.3.3 访问 setValue 方法的操作方法

     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
            //访问 setValue 方法的操作方法
            Student student = new Student("zhangsan");
            Class<? extends Student> claszz = student.getClass();
            Method m = claszz.getMethod("setValue", new Class[]{String.class});
            m.invoke(student, new Object[]{"张三"});
            System.out.println(student.toString());
    
        }
    

    1.3.4 访问类的有参构造方法

     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            //访问类的有参构造方法
            Class<?> clazz = Class.forName("reflection.Student");
            Constructor<?> constructor = clazz.getConstructor(new Class[]{String.class});
            Student student= (Student)constructor.newInstance(new Object[]{"陈飞"});
            System.out.println("----->>>>-----"+student);
        }
    

    1.4 如何使用反射机制

    使用反射机制,就是因为不知道运行的时候不知道使用哪一个类,所以就需要运行的时候动态加载。先加载动态的类,然后再解析类。最后使用反射API对类的成员信息进行访问。

    1.5 静态代理

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类

    public interface Subject {
        public  int add(int a ,int b);
    }
    
    public class ReadSubject implements  Subject {
        @Override
        public int add(int a, int b) {
            return a+b;
        }
    }
    
    public class Proxy implements Subject {
    
        private Subject subject=null;
    
        public Proxy(Subject subject) {
            this.subject = subject;
        }
    
        @Override
        public int add(int arg1, int arg2) {
            System.out.println("被加数为:"+arg1);
            System.out.println("加数为:"+arg2);
            return subject.add(arg1, arg2);
        }
    }
    
    public class ProxyTest {
        public static void main(String[] args) {
            Subject subject = new Proxy(new ReadSubject());
            int resulr=subject.add(1,4);
            System.out.println(resulr);
        }
    }
    

    1.6动态代理

    静态代理解决了业务逻辑与日志信息脱耦的一种设计, 但是又带来其他的问题, 也就是
    说我们有 100 个目标对象,就需要设计 100 个代理,这样会引起类爆炸(类非常多) 。
    代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

    public class DynamicProxy implements InvocationHandler {
        private  Object object=null;
         public Object biding(Object object){
             this.object=object;
             return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
         }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result=null;
            for (Object o:args){
                System.out.println(o);
            }
            result=method.invoke(object,args);
            return result;
        }
    }
    
    public class DymicProxyTest {
        public static void main(String[] args) {
            DynamicProxy dynamicProxy = new DynamicProxy();
            Subject biding = (Subject)dynamicProxy.biding(new ReadSubject());
            int resultt=biding.add(1,6);
            System.out.println(resultt);
        }
    }
    

    1.7 创建对象的几种方式

    • 使用new关键字:这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们还可以调用任意的够赞函数(无参的和有参的)。比如:Student student = new Student()

    • 使用Class类的newInstance方法:我们也可以使用Class类的newInstance方法创建对象,这个newInstance方法调用无参的构造器创建对象,如:Student student2 = (Student)Class.forName("根路径.Student").newInstance(); 或者:Student stu = Student.class.newInstance();

    • 使用Constructor类的newInstance方法:本方法和Class类的newInstance方法很像,java.lang.relect.Constructor类里也有一个newInstance方法可以创建对象。我们可以通过这个newInstance方法调用有参数的和私有的构造函数。如: Constructor<Student> constructor = Student.class.getInstance(); Student stu = constructor.newInstance(); 这两种newInstance的方法就是大家所说的反射,事实上Class的newInstance方法内部调用Constructor的newInstance方法。这也是众多框架Spring、Hibernate、Struts等使用后者的原因。

    • 使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。要使用clone方法,我们必须先实现Cloneable接口并实现其定义的clone方法。如:Student stu2 = <Student>stu.clone();这也是原型模式的应用。

    • 使用反序列化:当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口。如:ObjectInputStream in = new ObjectInputStream (new FileInputStream("data.obj")); Student stu3 = (Student)in.readObject();

    相关文章

      网友评论

          本文标题:第二节:反射学习

          本文链接:https://www.haomeiwen.com/subject/aarecxtx.html