反射使用方法

138 阅读3分钟

大家都知道,Java是面向对象的语言,在Java中我们可以通过类的对象访问变量,执行方法,对于方法,变量,类而言,其有固定修饰符(public protected private)表明其作用范围,那么我们如果要无视修饰符直接访问类的方法和变量应该怎么做呢?比如直接构造框架的private修饰的类的实例对象,访问某一对象的private成员等,此时就需要用到反射了。

反射是在运行状态下,直接操作类或对象内部属性的一种方法,其是破坏类封装性的一种表现,反射机制主要提供以下能力:

  • 运行时判断任意对象所属类的能力
  • 运行时构造任意类实例对象的能力
  • 运行时判断一个类所具有的成员变量和方法的能力
  • 运行时获取任意对象的任意成员和执行任意方法的能力

通过反射构造类并调用方法的流程如下:

  1. 获取类的Class对象

    // ClassName为String类型,是包含包名的全路径名称,比如com.example.hello下的A类,则
    // className = com.example.hello.A
    Class personClass = Class.forName(ClassName);
    
  2. 调用Class对象的newInstance方法

    // 调用class对象创建类的实例对象
    Object person = personClass.newInstance();
    
  3. 获取对象的Method

    // getMethod方法的第一个参数为方法名,随后的参数为参数类型,该函数为不定参函数
    // 参数类型顺序与函数声明顺序一致
    Method method = personClass.getMethod("setName", String.class);
    
  4. 执行Method

    // 针对构建的对象执行函数,第一个参数为对象,第二个参数为参数对应的取值
    // 取值传入顺序与函数声明的参数顺序一致,该函数为不定参函数
    method.invoke(person,"Hello");
    

接下来我们来看下反射调用Person类的示例代码,Person类声明如下图所示:

1-5-1-1

反射构造Person类对象,并调用setName,getName的实例代码及运行结果如下所示:

1-5-1-2

获取类的Class对象

一般情况下,我们有三种方式获取类的Class对象:

  • 通过Class.forName方法,适用于知道类的全路径的情况

  • 通过类的.class方法,适用于知道类名的情况

    Class clz = Person.class;
    
  • 通过类对象,适用于只有对象的情况

    Person personx = new Person("XXXX");
    Class cla = personx.getClass();
    

构造类的对象

一般情况下,我们有三种方式构造类的对象:

  • 通过Class对象的newInstance方法

    Object person = personClass.newInstance();
    
  • 通过Constructor对象的newInstance方法

    // getConstructor传入的为构造函数需要的参数,该函数为不定参函数
    Constructor constructor = clz.getConstructor(String.class);
    // newInstance传入的是参数具体的取值,该函数为不定参函数
    Object person1= constructor.newInstance("Hello");
    

    通过Constructor构造时,可以按需选择类的构造器相对而言更加灵活

反射获取类构造方法,属性和其他方法

  1. 获取类的公共成员:Class.getFields

    Class clz = Class.forName("com.example.code.Person");
    Field[] fileds = clz.getFields();
    for (Field field:fileds) {
        System.out.println(field.getName());
    }
    

    1-5-1-3

  2. 获取类的所有成员:Class.getDeclaredFields()[不包含父类成员]

    Class clz = Class.forName("com.example.code.Person");
    Field[] fileds = clz.getDeclaredFields();
    for (Field field:fileds) {
        System.out.println(field.getName());
    }
    

    1-5-1-4

  3. 获取类的所有公共方法:Class.getMethods()[包含父类公共方法]

    Class clz = Class.forName("com.example.code.Person");
    Method[] fileds = clz.getMethods();
    for (Method field:fileds) {
        System.out.println(field.getName());
    }
    

    1-5-1-5

  4. 获取类的所有方法:Class.getDeclaredMethods()[不包含父类方法]

    Class clz = Class.forName("com.example.code.Person");
    Method[] fileds = clz.getDeclaredMethods();
    for (Method field:fileds) {
        System.out.println(field.getName());
    }
    

    1-5-1-6

  5. 获取类的公共构造:Class.getConstructors

    Class clz = Class.forName("com.example.code.Person");
    Constructor[] fileds = clz.getConstructors();
    for (Constructor field:fileds) {
        System.out.println(field.getName());
    }
    

    1-5-1-7

  6. 获取类的所有构造函数:Class.getDeclaredConstructors()

    Class clz = Class.forName("com.example.code.Person");
    Constructor[] fileds = clz.getDeclaredConstructors();
    for (Constructor field:fileds) {
        System.out.println(field.getName());
    }
    

    1-5-1-8

  7. 利用反射创建数组

    1-5-1-9

  8. 使用反射获取类注解:Class.getAnnotations和Class.getDeclaredAnnotations