1.如何理解反射机制:
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
2.反射的具体应用:
- 原来使用new的时候,需要明确的指定类名,这个时候属于硬编码实现,而在使用反射的时候,可以只传入类名参数,就可以生成对象,降低了耦合性,使得程序更具灵活性。关于这一点的实例有:简单工厂模式的优化、Spring框架中Bean的创建、动态代理的实现等。
- 原来并未使用反射时,我们没办法在运行时动态获取/修改一个类的所有属性,而通过反射机制,我们能够在运行时确定类的状态和属性,这为灵活操作提供了空间。具体的实例有:运行时根据类的状态进行异常监测,突破封装限制获取修改private、protected属性,这点在IDE的调试器中就有应用。
3.反射API的基本概念:
- Class类:Java程序在编译完成后,会把所有class文件中所包含的类的基本元信息装载到JVM内存中,以Class类的形式保存,每一个Class类对象代表一个具体类的基本元信息。我们的反射就是在Class类的基础上进行的,Class类对象存储着类的所有相关信息,就像镜子,故称“反射”。
- Field:即类或对象的域,就是属性值
- Method:类或对象的方法
- Constructor:类或对象的构造器,使用它可以构造出相应的类对象
4.反射基本原理整体流程:
- 准备阶段:编译期装载所有的类,将每个类的元信息保存至Class类对象中,每一个类对应一个Class对象
- 获取Class对象:调用x.class/x.getClass()/Class.forName() 获取x的Class对象clz
- 进行实际反射操作:通过clz对象获取Field/Method/Constructor对象进行进一步操作
5.如何获取class对象:
第一种是从reflectionData直接取,reflectionData是弱引用,这算是一种缓存获取;
第二种是直接调用getDeclaredFields0()这个方法获取,这是一个native方法,应当是从JVM内直接获取
6.获取到的Method的调用过程:
- Method对象通过MethodAcessor的invoke调用方法 ->
- 通过反射工厂生成MethodAcessor对象 ->
- 生成NativeMethodAcessorImpl,最终由DelegatingMethodAccessorImpl代理 ->
- 调用时先进入的是DelegatingMethodAccessorImpl的invoke方法 ->
- DelegatingMethodAcessorImpl是代理对象,实质上最终调用的是NativeMethodAcessorImpl的invoke方法
- 所有的方法反射都是先走NativeMethodAccessorImpl,默认调了15次之后,才生成一个GeneratedMethodAccessorXXX类,生成好之后就会走这个生成的类的invoke方法了