反射

1. 反射机制的概念

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

下面是 Java 代码在计算机中三个阶段:

  1. Source 源码阶段:.java 文件被编译为 .class 字节码文件。
  2. Class 类对象阶段:.class 字节码文件被类加载器加载进内存,并将其封装成 Class 类对象。Class 类对象会将字节码文件中的各个组成部分封装为对应的数组。(如:成员变量数组 Field[] fields,构造方法数组 Constructor[] cons)
  3. Runtime 运行时阶段:使用 new 创建对象。
    在这里插入图片描述

2. 反射的用处

  • 可以在程序运行过程中,操作对象。
  • 可以解耦合,提高程序的可拓展性。

3. 反射的使用

3.1 获取 Class 对象

前面我们讲了"Class 类对象会将字节码文件中的各个组成部分封装为对应的数组",而我们要操作这些数组,首先就要获得类对象。

获得类对象的方式有三种:

  1. Class.forName(“全类名”):将字节码文件加载进内存,返回 Class 对象。

    (多用于配置文件,将类名定义在配置文件中。读取文件,加载类)

  2. 类名.class:通过类名的属性 class 获取。

    (多用于参数的传递)

  3. 对象.getClass():getClass() 方法是在 Object 类中定义的。

    (多用于对象的获取字节码的方式)

在这里插入图片描述

接下来验证上面的三个对象是否是同一对象

在这里插入图片描述
结果是同一对象,于是得出结论:

同一个字节码文件在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

3.2 Class 对象的方法

  • 获取成员变量
    • Field[] getFields():获取所有 public 修饰的成员变量
    • Field getField(String name):获取指定名称的 public 修饰的成员变量
    • Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
    • Field getDeclaredField(String name):获取指定名称的成员变量,不考虑修饰符
  • 获取构造方法
    • Constructor<?>[] getConstructors()
    • Constructor getConstructor(Class<?>… parameterTypes)
    • Constructor<?>[] getDeclaredConstructors()
    • Constructor getDeclaredConstructor(Class<?>… parameterTypes)
  • 获取成员方法
    • Method[] getMethods()
    • Method getMethod(String name, Class<?>… parameterTypes)
    • Method[] getDeclaredMethods()
    • Method getDeclaredMethod(String name, Class<?>… parameterTypes)
  • 获取全类名
    • String getName()

3.3 操作对象

前面根据 Class 对象的方法已经可以获得类的各个组成部分了,下面用这些组成部分来操作具体的对象。

  • Field:成员变量

    • 获取值:Object get(Object obj)
    • 设置值:void set(Object obj, Object value)
    • 忽略访问权限修饰符的安全检查:setAccessible(true)
  • Constructor:构造方法

    • 创建对象:T newInstance(Object… initargs)

      补充:如果使用空参数构造方法创建对象,可以直接用 Class 对象的 newInstance 方法创建

  • Method:方法对象

    • 执行方法:Object invoke(Object obj, Object… args)
    • 获取方法名称:String getName()

4. 反射的案例

  1. 需求分析

    写一个“框架",在不改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法。

  2. 概要设计

    先在配置文件中写好我们要创建对象的全类名和方法名,然后在程序中加载并读取配置文件,然后加载该类进内存,之后创建对象,再利用反射获取需要执行的方法,最后执行方法。

  3. 详细设计

    1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件 pro.properties 中
    2. 在程序中加载配置文件到 properties 集合中
    3. 从 properties 集合中获取配置文件中定义的数据
    4. 根据全类名加载该类进内存,获取对应的 Class 对象
    5. 创建对象
    6. 利用反射获取需要执行的方法
    7. 执行该方法
  4. 编码实现

    • pro.properties(配置文件)

      className=com.zt.domain.Person
      methodName=getName
      
    • ReflectTest

      public class ReflectTest {
          public static void main(String[] args) throws Exception {
              //1. 加载配置文件到 properties 集合中
              //1.1 创建 properties 对象,它相当于一个 Map 集合
              Properties properties = new Properties();
              //1.2 通过类加载器获取 class 目录下配置文件的路径
              ClassLoader classLoader = ReflectTest.class.getClassLoader();
              InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
              //1.3 加载配置文件到 properties 集合中
              properties.load(resourceAsStream);
      
              //2. 从 properties 集合中获取配置文件中定义的数据
              String className = properties.getProperty("className");
              String methodName = properties.getProperty("methodName");
      
              //3. 根据全类名加载该类进内存,获取对应的 Class 对象
              Class<?> aClass = Class.forName(className);
      
              //4. 创建对象
              Object o = aClass.newInstance();
      
              //5. 利用反射获取方法
              Method method1 = aClass.getMethod(methodName);
      
              //6. 执行该方法
              System.out.println(method1.invoke(o));
          }
      }
      
      
    • 执行结果

      null
      
      Process finished with exit code 0
      
      
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bm1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值