Java 反射(Reflection) 是一种在运行时(Runtime)动态获取、检查和修改类、方法、属性等程序结构的能力,是Java语言的核心特性之一。它打破了封装性,允许程序在编译期未知具体类信息的情况下操作对象。
核心作用
- 动态获取类信息
- 在运行时获取类的完整结构(类名、父类、接口、方法、字段、注解等)。
- 动态操作对象
- 创建对象、调用方法、修改字段值(包括私有成员)。
- 突破访问限制
- 通过反射可绕过
private
等访问修饰符的限制(需谨慎使用)。
- 通过反射可绕过
关键API(java.lang.reflect
包)
类/接口 | 作用 |
---|---|
Class | 表示类的元数据(核心入口) |
Field | 获取和修改类的字段(包括私有字段) |
Method | 动态调用类的方法(包括私有方法) |
Constructor | 创建类的实例 |
Annotation | 读取类/方法/字段上的注解 |
使用场景示例
1. 动态创建对象
// 通过全限定类名创建实例
Class<?> clazz = Class.forName("com.example.User");
Object user = clazz.newInstance(); // 调用无参构造
2. 调用私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true); // 突破私有限制
privateMethod.invoke(user); // 执行方法
3. 修改私有字段
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(user, "NewName"); // 修改字段值
4. 获取注解信息
Annotation[] annotations = clazz.getAnnotations(); // 获取类上的所有注解
反射的优缺点
优点 | 缺点 |
---|---|
✅ 动态扩展功能(如框架底层实现) | ❌ 破坏封装性,安全性降低 |
✅ 实现通用工具(如JSON序列化) | ❌ 性能开销大(比直接调用慢) |
✅ 支持注解解析 | ❌ 代码可读性差,调试困难 |
典型应用场景
- 框架开发
- Spring(依赖注入)、Hibernate(ORM)、JUnit(测试框架)均依赖反射。
- 动态代理
- 实现AOP编程(如Spring AOP)。
- IDE工具
- IntelliJ IDEA的代码提示、调试器依赖反射获取类信息。
- 注解处理器
- 编译期/运行时解析注解(如Lombok)。
性能优化建议
// 缓存频繁使用的反射对象
private static final Method methodCache;
static {
methodCache = SomeClass.class.getDeclaredMethod("methodName");
methodCache.setAccessible(true);
}
// 后续重复使用methodCache.invoke()而非重新获取
注意:现代JVM对反射调用有优化(如
MethodHandle
),但直接代码调用仍比反射快。除非必要(如框架开发),否则优先使用常规编程方式。