zoukankan      html  css  js  c++  java
  • 反射详解

    一、啥是反射?

      通过反射机制加载一个class字节码文件,获得并调用任意一个类的所有属性和方法。

    二、反射能干啥?

    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时调用任意一个对象的方法

    三、干一干试试看!

    1. Animal样本类

    public class Animal {
        public String name = "Dog";
        private int age = 3;
        public Animal(){
            System.out.println("Public-Animal");
        }
        public Animal(String name){
            System.out.println("Public-Animal:name"+name);
        }
        private Animal(String name, int age){
            System.out.println("Private-Animal:name:" + name + ",age:" + age );
        }
        public String sayName(String name){
            return "Hello," + name;
        }
    }

    2. ReflectTest测试类

    public class ReflectTest {
        public static void main(String[] args) throws Exception {
            //获取Class对象的三种方式
            Class animal = Class.forName("com.reflect.Animal");
            Class animal_2 = Animal.class;
            Animal animalObj = new Animal();
            Class animal_3 = animalObj.getClass();
            System.out.println(animal);//class com.reflect.Animal
            System.out.println(animal_2);//class com.reflect.Animal
            System.out.println(animal_3);//class com.reflect.Animal
            System.out.println(animal == animal_2);//true
            System.out.println(animal == animal_3);//true
    
            //获得成员变量
            //1.获得所有声明的成员变量
            Field[] declaredFieldList = animal.getDeclaredFields();
            for(Field field : declaredFieldList){
                System.out.println("DeclaredField"+field);
                //DeclaredFieldpublic java.lang.String com.reflect.Animal.name
                //DeclaredFieldprivate int com.reflect.Animal.age
            }
            //2.获得所有共有的成员变量
            Field[] pubFieldList = animal.getFields();
            for(Field field : pubFieldList){
                System.out.println("PublicField" + field);
                //PublicFieldpublic java.lang.String com.reflect.Animal.name
            }
    
            //获得构造器
            //1.获得所有声明的构造器
            Constructor[] declaredConst = animal.getDeclaredConstructors();
            for(Constructor constructor : declaredConst){
                System.out.println(constructor);
                //private com.reflect.Animal(java.lang.String,int)
                //public com.reflect.Animal(java.lang.String)
                //public com.reflect.Animal()
            }
            //2.获得所有共有的构造器
            Constructor[] pubConst = animal.getConstructors();
            for(Constructor constructor : pubConst){
                System.out.println(constructor);
                //public com.reflect.Animal(java.lang.String)
                //public com.reflect.Animal()
            }
    
            //获得非构造方法,具体不演示了
            //1.获得所有声明非构造方法
            Method[] declaredMethodList = animal.getDeclaredMethods();
            //获得公有非构造方法
            Method[] methodList = animal.getMethods();
        }
    }

    3. 进阶测试类

    public class ReflectDemo {
        public static void main(String[] args) throws Exception {
            // 1.通过字符串获取Class对象,这个字符串必须带上完整路径名
            Class animalClass = Class.forName("com.reflect.Animal");
    
            // 2.获取声明的构造方法,传入所需参数的类名,如果有多个参数,用','连接即可, private Animal(String name, int age)
            Constructor animalConstructor = animalClass.getDeclaredConstructor(String.class, Integer.class);
            // 如果是私有的构造方法,需要调用下面这一行代码使其可使用,公有的构造方法则不需要下面这一行代码
            animalConstructor.setAccessible(true);
            // 使用构造方法的newInstance方法创建对象,传入构造方法所需参数,如果有多个参数,用','连接即可
            Object animal = animalConstructor.newInstance("Cat",100);
    
            // 3.获取声明的字段,传入字段名  private int age = 3;
            Field animalgeField = animalClass.getDeclaredField("age");
            // 如果是私有的字段,需要调用下面这一行代码使其可使用,公有的字段则不需要下面这一行代码
            animalgeField.setAccessible(true);
            // 使用字段的set方法设置字段值,传入此对象以及参数值
            animalgeField.set(animal,10);
    // 4.获取声明的函数,传入所需参数的类名,如果有多个参数,用','连接即可 Method studentShowMethod = animalClass.getDeclaredMethod("sayName", String.class); // 如果是私有的函数,需要调用下面这一行代码使其可使用,公有的函数则不需要下面这一行代码 //studentShowMethod.setAccessible(true); // 使用函数的invoke方法调用此函数,传入此对象以及函数所需参数,如果有多个参数,用','连接即可。函数会返回一个Object对象,使用强制类型转换转成实际类型即可 Object result = studentShowMethod.invoke(animal,"message"); System.out.println("result: " + result);//result: Hello,message,age:10
        }
    }

    四、为啥这么搞,不是更复杂了吗?

      为啥不直接使用当前类的方法属性,而是利用反射通过class文件获取呢?

      举例:Spring IOC容器进行Bean管理,在Spring中我们经常看到:

       Spring就是通过配置文件中class路径进行反射处理获得对应的对象。这样便可以根据不同的配置进行相应的处理。而不需要每次都要new一个,不把代码写死。

    //解析<bean .../>元素的id属性得到该字符串值为"sqlSessionFactory" 
            String idStr = "sqlSessionFactory";  
            //解析<bean .../>元素的class属性得到该字符串值为"org.mybatis.spring.SqlSessionFactoryBean"  
            String classStr = "org.mybatis.spring.SqlSessionFactoryBean";  
            //利用反射知识,通过classStr获取Class类对象  
            Class cls = Class.forName(classStr);  
            //实例化对象  
            Object obj = cls.newInstance();  
            //container表示Spring容器  
            container.put(idStr, obj);  
            
            //当一个类里面需要用另一类的对象时,我们继续下面的操作
            
            //解析<property .../>元素的name属性得到该字符串值为“dataSource”  
            String nameStr = "dataSource";  
            //解析<property .../>元素的ref属性得到该字符串值为“dataSource”  
            String refStr = "dataSource";  
            //生成将要调用setter方法名  
            String setterName = "set" + nameStr.substring(0, 1).toUpperCase()  
                    + nameStr.substring(1);  
            //获取spring容器中名为refStr的Bean,该Bean将会作为传入参数  
            Object paramBean = container.get(refStr);  
            //获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象  
            Method setter = cls.getMethod(setterName, paramBean.getClass());  
            //调用invoke()方法,此处的obj是刚才反射代码得到的Object对象  
            setter.invoke(obj, paramBean);  

    总结

    • 反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
    • 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码。
    • 测试时可以利用反射 API 访问类的私有成员,以保证测试代码覆盖率。
  • 相关阅读:
    ccr1
    与非CCR代码互操作
    ccr test
    CCR
    tpl + ccr
    TPL
    利用 Rational ClearCase ClearMake 构建高性能的企业级构建环境
    Android错误:Re-installation failed due to different application signatures
    C 单例模式
    C 工厂模式 还有其他的模式
  • 原文地址:https://www.cnblogs.com/qmillet/p/12503090.html
Copyright © 2011-2022 走看看