反射是什么?
反射(Reflection)是 JVM 提供的运行时机制 ,它允许程序在运行期借助 Reflection API 动态加载类或获取任何类的内部信息,动态创建对象并调用其属性,即使对象类型在编译期还是未知的。而我们通常写的程序,对象的类型是在编译期就确定下来的。就像上面说到的饭店的菜单,每道菜品是固定的,无法变更。
而反射赋予了我们动态创建菜品和调整菜品的能力。所以说,虽然 Java 是一种静态语言,但是反射机制的存在使 Java 也具有了动态性,具备了运行时自我认知的能力。这样我们就可以在运行时观察甚至修改 JVM 的行为。就像进入饭店的后厨,可以观察甚至调整我们的菜品。
反射的实现原理
反射机制的实现依赖于我们前两节课讲过的类加载机制,我们知道类加载的结果,除了把类的.class 文件中的二进制数据读入内存,并放到运行时数据区的方法区,JVM 还为我们在堆上创建了一个 java.lang.Class 对象,用来封装类在方法区内的数据结构,并且向我们提供了访问方法区内的数据结构的接口。
这个 Class 对象就是反射机制的核心,它就像打开 JVM 这个厨房的钥匙,赋予了我们打造专属于自己的菜品的能力。是不是感觉很酷,那我们应该怎么更好地利用这种能力呢?
反射执行步骤
有了上述 API ,我们可以按下面的步骤完成反射机制的调用。
我们需要先获取想要操作的类的 Class 对象。
通过调用 Class 类中的方法,获得我们需要的 Method、Field 类对象。
借助反射 API,操作这些对象,完成定制。
获取 Class 对象
获得这把钥匙的方式有 3 种。
• Class.forName
使用 Class 类的静态方法 forName(String className),这种方法需要传入类的全限定名,可以动态加载类,并触发静态代码块的执行,一般用于加载驱动和框架的底层操作。但是因为这个方法可能会抛出 ClassNotFoundException 异常,所以你需要处理这种可能性。
• .class 语法
对于任何类型的.class 都可以获取对应的 Class 对象。这是最直接、最简单的方式,不需要处理异常,但弊端也很明显,就是必须在编译期就知道具体的类,类似于厨房里本可以提供 100 道菜,但是菜单上只是写了 10 道菜,而你只能操作这菜单上面的 10 道菜,动态性大打折扣。
• Object 类的方法 getClass()
这种方法不需要类的完全限定名,只需要获取对象实例的类型。但是,你需要一个对象实例,所以在没有实例的情况下这种方法就没办法使用了。
第二层境界:运行时动态扩展 JVM 的提供能力
动态创建对象
当需要基于运行时的条件创建不同类型的对象时,反射机制是必需的。
创建对象有两种方法。
使用 Class 对象的 newInstance() 方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。
先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance() 方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例。
第三层境界:基于 JVM 提供的能力打造一个定制的图灵机
其实我们非常熟悉的 Spring 框架 ,正是借助反射机制,实现了我们说的使用 JVM 的第三层境界。Spring 封装了 JVM 底层的能力,通过 Bean 对外提供服务,而不是使用 Java 的 Object,这里的 Bean 就像我们封装了饭店后厨的能力打造的新菜单。
而这一切都离不开反射机制的支持,不管是依赖注入还是 AOP 编程,都使用到了反射机制。比如在依赖注入时,Spring 会通过反射调用 Bean 的 setter 方法或者构造器来实现依赖关系的注入;在 AOP 编程中,Spring 则是通过反射调用目标方法,并在调用之前或之后添加增强处理,从而实现面向切面编程。
为了方便你看清其中的本质,我把反射在 Spring 中的应用过程抽象成了 3 个步骤。
第一步:Spring 通过反射的方式创建 Bean 实例。在 Spring 中,对于配置的 Bean,其创建工作是由 BeanFactory 完成的。在 AbstractBeanFactory 类的 doCreateBean 方法中,调用 createBeanInstance 方法创建 Bean 实例,这个过程使用了反射技术。
第二步:Spring 通过反射设置属性值。在 BeanPostProcessor 后置处理器中,Spring 会读取属性配置,使用反射调用 set 方法为 Bean 的属性设置值。
第三步:Spring 通过反射调用 Bean 的生命周期回调方法,如 init-method 和 destroy-method。
此文章为9月Day11学习笔记,内容来源于极客时间《云时代JVM实战 》,强烈推荐该课程










网友评论