JAVA - 反射

作者: AntiGravity | 来源:发表于2017-10-09 20:35 被阅读0次

    一、理解

    概念

    反射是JAVA的一个机制。

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

    每个类被加载之后,系统就会为该类生成一个对应的Class对象。通过该Class对象就可以访问到JVM中的这个类。

    应用

    1. 获取程序在运行时刻的内部结构

    这对于程序的检查工具和调试器来说,是非常实用的功能。只需要短短的十几行代码,就可以遍历出来一个Java类的内部结构,包括其中的构造方法、声明的域和定义的方法等。这不得不说是一个很强大的能力。只要有了java.lang.Class类 的对象,就可以通过其中的方法来获取到该类中的构造方法、域和方法。对应的方法分别是getConstructorgetFieldgetMethod。这三个方法还有相应的getDeclaredXXX版本,区别在于getDeclaredXXX版本的方法只会获取该类自身所声明的元素,而不会考虑继承下来的。ConstructorFieldMethod这三个类分别表示类中的构造方法、域和方法。这些类中的方法可以获取到所对应结构的元数据。

    2. 在运行时刻对一个Java对象进行操作

    这些操作包括动态创建一个Java类的对象,获取某个域的值以及调用某个方法。在Java源代码中编写的对类和对象的操作,都可以在运行时刻通过反射API来实现。

    二、使用

    取得Class对象

    每个类被加载之后,系统就会为该类生成一个对应的Class对象。通过该Class对象就可以访问到JVM中的这个类。
    在Java程序中获得Class对象通常有如下三种方式:

    1. 使用 Class 类的forName(String clazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定名(必须添加完整包名)。
    2. 调用某个类的class属性来获取该类对应的 Class 对象。
    3. 调用某个对象的getClass()方法。该方法是java.lang.Object类中的一个方法。
    //第一种方式 通过Class类的静态方法——forName()来实现
    class1 = Class.forName("com.lvr.reflection.Person");
    //第二种方式 通过类的class属性
    class1 = Person.class;
    //第三种方式 通过对象getClass方法
    Person person = new Person();
    Class<?> class1 = person.getClass();
    

    对于方式一和方式二都是直接根据类来取得该类的 Class 对象,相比之下,方式二有如下的两种优势:

    • 代码更安全。程序在编译阶段就能够检查需要访问的 Class 对象是否存在。
    • 线程性能更好。因为这种方式无须调用方法,所以性能更好。

    可以通过类的类类型创建该类的对象实例。

    //Class.newInstance();
    Foot foot = (Foot) c1.newInstance();
    

    从class中获取信息(常用)

    一旦获得了某个类所对应的Class 对象之后,就可以调用 Class 对象的方法来获得该对象的和该类的真实信息了。

    1. 获取 Class 对应类的成员变量
    Field[] getDeclaredFields(); // 获取 Class 对象对应类的所有属性,与成员变量的访问权限无关。
    Field[] getFields(); // 获取 Class 对象对应类的所有 public 属性。
    Field getDeclaredField(String name); // 获取 Class 对象对应类的指定名称的属性,与成员变量的访问权限无关。
    Field getField(String name); // 获取 Class 对象对应类的指定名称的 public 属性。
    
    2. 获取 Class 对应类的方法
    Method[] getDeclaredMethods(); // 获取 Class 对象对应类的所有声明方法,于方法的访问权限无关。
    Method[] getMethods(); // 获取 Class 对象对应类的所有 public 方法,包括父类的方法。
    Method getMethod(String name, Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的 public 方法。
    Method getDeclaredMethod(String name, Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的方法,与方法的访问权限无关。
    
    3. 获取 Class 对应类的构造函数
    Constructor<?>[] getDeclaredConstructors(); // 获取 Class 对象对应类的所有声明构造函数,于构造函数的访问权限无关。
    Constructor<?>[] getConstructors(); // 获取 Class 对象对应类的所有 public 构造函数。
    Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的构造函数,与构造函数的访问权限无关。
    Constructor<T> getConstructor(Class<?>...parameterTypes); // 返回此 Class 对象对应类的、带指定形参列表的 public 构造函数。
    

    (不常用)

    4. 获取 Class 对应类的 Annotation(注释)
    <A extends Annotation>A getAnnotation(Class<A> annotationClass); // 尝试获取该 Class 对对象对应类存在的、指定类型的 Annotation;如果该类型的注解不存在,则返回 null。
    <A extends Annotation>A getDeclaredAnnotation(Class<A> annotationClass); // 这是Java8新增的方法,该方法尝试获取直接修饰该 Class 对象对应类、指定类型的Annotation;如果该类型的注解不存在,则返回 null。
    Annotation[] getAnnotations(); // 返回修饰该 Class 对象对应类存在的所有Annotation。
    Annotation[] getDeclaredAnnotations(); // 返回直接修饰该 Class 对应类的所有Annotation。
    <A extends Annotation>A[] getAnnotationsByType(Class<A> annotationClass); // 获取修饰该类的、指定类型的多个Annotation。
    <A extends Annotation>A[] getDeclaredAnnotationsByType(Class<A> annotationClass); // 获取直接修饰该类的、指定类型的多个Annotation。
    
    5. 获取 Class 对应类的内部类
    Class<?>[] getDeclaredClasses(); // 返回该 Class 对象对应类包含的全部内部类。
    
    6. 获取 Class 对应类的外部类
    Class<?> getDeclaringClass(); // 返回该 Class 对象对应类所在的外部类。
    
    7. 获取 Class 对应类所实现的接口
    Class<?>[] getInterfaces();
    
    8. 获取 Class 对应类所继承的父类
    Class<? super T> getSuperClass();
    
    9. 获取 Class 对应类的修饰符、所在包、类名等基本信息
    int getModifiers(); // 返回此类或接口的所有修饰符。修饰符由 public、protected、private、final、static、abstract 等对应的常量组成,返回的整数应使用 Modifier 工具类的方法来解码,才可以获取真实的修饰符。
    Package getPackage() // 获取该类的包。
    String getName() // 以字符串的形式返回此 Class 对象所表示的类的名称。
    String getSimpleName() // 以字符串的形式返回此 Class 对象所表示的类的简称。
    
    10. 判断该类是否为接口、枚举、注解类型等
    boolean isAnnotation() // 返此 Class 对象是否是一个注解类型(由@interface定义)。
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // 判断此 Class 对象是否使用了Annotation修饰。
    boolean isAnonymousClass() // 此 Class 对象是否是一个匿名类。
    boolean isArray() //此 Class 对象是否是一个数组。
    boolean isEnum() // 此 Class 对象是否是一个枚举(由 enum 关键字定义)。
    boolean isInterface() // 此 Class 对象是否是一个接口(由 interface 关键字定义)。
    boolean isInstance(Object obj) // 判断 obj 是否是此 Class 对象的实例。该方法完全可以替代 instanceof 操作符。
    

    相关文章

      网友评论

        本文标题:JAVA - 反射

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