一.什么是反射机制

java的反射机制是在运行状态中: 对于任意一个类,都能够知道这个类中的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制。

这里的运行状态,个人理解是相对于编译时的,因为java的类在创建后,以使用new来创建为例,jvm会把代码编译成.class文件然后被类加载器加载到内存中,其中new的类会放入方法区,而类的class对象也就是类型对象会放入堆中,这个class对象每个类只有一个,也是提供方法区实例化的类的数据结构的接口。这是类的加载过程详细的后面我再了解说明下,这样如果我们在jvm正在运行时加载一些之前可能用不到所以没有加载到jvm内存中的类的话,就需要反射来动态的实例化类或者调用类的一些方法。

那反射有哪些具体的功能呢?

  1. 在运行时判断任意一个对象所属的类。
  2. 在运行时构造任意一个类的对象。
  3. 在运行时判断任意一个类所具有的成员变量和方法。
  4. 在运行时调用任意一个对象的方法。
  5. 生成动态代理。

反射的使用场景应该都看到过很多次了,就是在逆向代码(如反编译); 与注解相结合的框架(如Retrofit); 单纯的反射机制应用框架(如EventBus); 动态生成类框架(如Gson)

二.获取类的信息

  1. java中获得class对象通常有三种方式: 一是使用Class类的static Class<?> forName(String className)静态方法,传入的字符串参数值是某个类的全限定名(必须添加完整包名);二是调用某个类的class属性来获取该类对应的Class对象;三是调用某个对象的getClass()方法
   public static void main(String[] args) {
        //通过forName()静态方法实现
        try {
            Class<?> class1 = Class.forName("com.dyh.demo.Book");
            System.out.println("通过forName静态方法获取的类: " + class1);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //通过类的class的属性
        Class<?> class2 = Book.class;
        System.out.println("通过类的class的属性获取的类: " + class2);
        //通过对象的getClass方法
        Book book = new Book();
        Class<?> class3 = book.getClass();
        System.out.println("通过类的class的属性获取的类: " + class3);
    }复制代码
  1. 获取class对象的属性,方法成员变量等
        /**
         * 获取class对象的成员变量
         */
        //获取class对象的所有属性
        Field[] allFields = class3.getDeclaredFields();
        System.out.println("class对象的所有属性: " + Arrays.toString(allFields));
        //获取class对象的public属性
        Field[] publicFields = class3.getFields();
        System.out.println("class对象的public属性: " + Arrays.toString(publicFields));
        //获取class对象的指定属性
        Field authorField = class3.getDeclaredField("author");
        System.out.println("class对象的指定属性: " + authorField);
        //获取class对象的指定public属性
        Field versionField = class3.getField("version");
        System.out.println("class对象的指定public属性: " + versionField);

        /**
         * 获取class对象的方法
         */
        //获取class对象的所有声明方法
        Method[] methods = class3.getDeclaredMethods();
        System.out.println("class对象的所有声明方法: " + Arrays.toString(methods));
        //获取class对象的public方法包括父类的方法
        Method[] allMethods = class3.getMethods();
        System.out.println("class对象的public方法包括父类的方法: " + Arrays.toString(allMethods));
        //获取class对象对应类的,带指定形参列表的public方法
        Method method = class3.getMethod("author", String.class);
        System.out.println("class对象的对应类的,带指定形参列表的public方法: " + method);
        //获取class对象的对应类的,带指定形参列表的方法
        Method declareMethod = class3.getDeclaredMethod("author", String.class);
        System.out.println("class对象的对应类的,带指定形参列表的方法: " + declareMethod);

        /**
         * 获取class对象的构造方法
         */
        //获取class对象的所有声明构造函数
        Constructor<?>[] allConstructors = class3.getDeclaredConstructors();
        System.out.println("class对象的所有声明构造函数: " + Arrays.toString(allConstructors));
        //获取class对象的public构造函数
        Constructor<?>[] publicConstructors = class3.getConstructors();
        System.out.println("class对象的public构造函数: " + Arrays.toString(publicConstructors));
        //获取class指定声明的构造方法
        Constructor<?> constructor = class3.getDeclaredConstructor(String.class);
        System.out.println("class指定声明的构造方法: " + constructor);
        //获取class指定声明的public构造方法
        Constructor<?> publicConstructor = class3.getConstructor(String.class);
        System.out.println("class指定声明的public构造方法: " + publicConstructor);

        /**
         * 获取class对象的其他方法
         */
        //获取class对象的所有注解
        Annotation[] annotations = (Annotation[]) class3.getAnnotations();
        System.out.println("class对象的所有注解: " + Arrays.toString(annotations));
        //获取class对象的指定注解
        Annotation annotation = (Annotation) class3.getAnnotation(Deprecated.class);
        System.out.println("class对象的指定注解: " + annotation);
        //获取class对象的直接超类的Type
        Type superClass = class3.getGenericSuperclass();
        System.out.println("class对象的直接超类的Type: " + superClass);
        //获取class对象的所有接口的type集合
        Type[] interfaceTypes = class3.getGenericInterfaces();
        System.out.println("class对象的所有接口的type集合: " + Arrays.toString(interfaceTypes));复制代码

3.获取class对象的信息

        //判断是否是基础类型
        boolean isPrimitive = class2.isPrimitive();
        //判断是否是集合类
        boolean isArray = class2.isArray();
        //判断是否是注解类
        boolean isAnnotation = class2.isAnnotation();
        //判断是否是接口类
        boolean isInterface = class2.isInterface();
        //判断是否是枚举类
        boolean isEnum = class2.isEnum();
        //判断是否是匿名内部类
        boolean isAnonymousClass = class2.isAnonymousClass();
        //判断是否被某个注解类修饰
        boolean isAnnotationPresent = class2.isAnnotationPresent(Documented.class);
        //获取class名字包括包名
        String className = class2.getName();
        //获取包信息
        Package aPackage = class2.getPackage();
        //获取类名
        String simpleName = class2.getSimpleName();
        //获取class访问权限
        int modifiers = class2.getModifiers();
        //内部类
        Class<?>[] declaredClasses = class2.getDeclaredClasses();
        //外部类
        Class<?> declaringClass = class2.getDeclaringClass();复制代码

三.通过反射操作对象

  1. 生成类的实例对象: 一种方法是使用newInstance()方法创建Class对象对应类的实例(这种方式的条件是Class对象的对应类有默认的构造函数,使用newInstance()方法实际上就是调用默认的构造函数来new一个实例。)使用方法是: Object obj = class.newInstance(); 还有一种方法是先获取到指定的构造函数(上面已经给出了获取class对象各个构造方法的函数),在通过调用获取到的构造方法的newInstance()方法来创建该class对象对应类的实例。

  2. 调用类的方法: 上面提到了获取class对象的各个方法的函数,获取到了想要动态使用的方法后,调用Method的Object invoke(Object obj, Object... args) 方法来使用。(第一个参数对应调用该方法的实例对象,第二个参数对应该方法的参数)具体使用方式:

     //生成一个实例对象
     Object obj = class2.newInstance();
     //获取需要的方法
     Method method = class2.getDeclaredMethod("setAuthor", String.class);
     //调用函数并传参
     method.invoke(obj, "dyh");复制代码

当然如果想要调用class对象对应类的方法,必须要有对应调用该方法的权限,如果某个方法是private的,可以使用method.setAccessible(boolean flag)来指定是否取消权限检查,设置true时,则取消java的访问权限检查。

  1. 使用成员变量: 在之前获取到成员变量的基础上,可以通过Field的getT(Object obj)方法来获取obj对象对应的成员变量的值,通过setT(Object obj, T value) 来设置obj对象对应的成员变量的值。T 是泛型,这里替代java的8种基本类型。