18 反射
1. 反射机制
-
反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员变量、构造器、成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到;
-
加载完类之后,在堆中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构,这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以,形象地称之为:反射
-
Java反射机制原理示意图
- 类编译阶段(代码阶段)【JVM底层】
通过Javac编译后,会生成对应的字节码文件,包含其属性、方法等等信息
- 类加载阶段(Class类阶段)【JVM底层】
当运行阶段,创建了一个对象(new)时,会导致类的加载。此时会把编译阶段的字节码文件加载到内存的堆里,生成一个Class类对象,在堆里。包含成员变量、构造器、成员方法等等其它信息。
在这个过程中,字节码文件如何生成Class对象并且放在堆里呢?是通过类的加载器(ClassLoader)完成的,这个过程其实就体现了反射机制。
在堆里生成的Class对象,其实是个数据结构,在底层,会把成员变量映射成,或者说当作一个对象来看待。比如说成员变量会对应成一个数组 Field[] fields,构造器也会当成一种对象,这个对象的类型就是 Constructor,可能有多个构造器,所以也会映射成数组,成员方法等等类似。
- 运行阶段【应用】
new一个对象,进行类加载过后会生成这个对象,这个对象也在堆中,该对象能知道自己属于哪个Class对象。
得到Class对象后,就可以创建对象,调用对象方法,操作属性等等。
- Java反射机制可以完成:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时德奥任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
- 反射相关的主要类
-
反射的优缺点:
优点: 可以多态的创建和使用对象(也是框架底层核心),灵活使用,没有反射机制,框架技术就失去底层支撑。
缺点:使用反射基本是解释执行,堆执行速度有影响。 -
反射调用优化——关闭访问检查
- Method 和 Field、Constructor 对象都有 setAccessible()方法
- setAccessible 作用是启动和禁用访问安全检查的开关
- 参数值为 true 表示 反射的对象在使用时取消访问检查,提高反射的效率。参数值为 false则表示反射的对象执行访问检查
2. Class类
- Class也是类,因此也继承 Object类
- Class类对象不是 new出来的,而是系统创建的(Class类对象是通过类加载器生成的,具体是loadClass方法完成类加载,然后生成某个类对应的Class对象)
- 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class对象可以完整地得到一个类的完整结构,通过一系列API
- Class对象是存放在堆的
7.类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等等)
-
Class类的常用方法
-
获取 Class类对象
-
如下类型有Class对象
3. 类加载
3.1 基本说明
反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载
- 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
- 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
3.2 类加载时机
- 当创建对象(new)时;静态加载
- 当子类被加载时,父类也加载;静态加载
- 调用类中的静态成员时;静态加载
- 通过反射;动态加载
3.3 类加载过程图
3.4 类加载各阶段完成任务
3.4.1 加载阶段
3.4.2 连接阶段-验证
3.4.3 连接阶段-准备
3.4.4 连接阶段-解析
3.4.5 初始化Initialization
4. 反射获取类的结构信息
-
通过反射获取类的结构信息
-
通过反射创建对象