反射
反射 = 通过类名获取 JVM 中的 Class 实例 → 进而创建该类的对象 或 获取其方法/字段/构造器等信息。
1 2 3 4 5 6 7 8
| Class<?> clazz = Class.forName("java.util.ArrayList");
Object obj = clazz.newInstance();
Method[] methods = clazz.getDeclaredMethods();
|
什么是反射?
反射(Reflection) 允许程序在运行时动态地检查、修改或调用类、方法、属性、构造函数等代码结构的信息。
打破了传统”编译时绑定”的限制,适配未知或变化的类型,增加程序的灵活性和通用性。
反射的本质
- JVM 为每个加载的
class 及 interface 创建对应的 Class 实例,保存其所有信息
- 获取
Class 实例后,即可获取该类的全部信息(方法、字段、构造器等)
- 通过
Class 实例获取类信息的方式称为反射
- JVM 动态加载 class,可在运行期根据条件控制加载
使用场景
| 场景 |
说明 |
| 框架开发 |
Spring 的依赖注入、AOP 的动态代理 |
| 动态加载类 |
插件化架构,运行时加载外部模块 |
| 序列化/反序列化 |
JSON 库(如 Gson、Jackson)对象与字符串互转 |
| 测试工具 |
JUnit 动态调用测试方法 |
注意事项与避坑方案
反射的风险
| 风险 |
说明 |
| 性能开销 |
反射操作比直接调用慢(绕过 JVM 优化) |
| 安全风险 |
可访问私有成员,破坏封装性 |
| 维护困难 |
代码可读性差,编译期无法检查,调试复杂 |
避坑方案
| 方案 |
实践 |
| 高频场景避免直接使用 |
用 MyBatis-Plus 的 Lambda 查询替代反射拼接 SQL |
| 缓存反射对象 |
缓存获取的 Method/Field 对象(Spring 内部做法) |
| 使用优化框架 |
用 CGLIB、ASM 替代原生反射 |