Java 反射机制
反射是程序在运行时动态访问、检测和修改自身状态或行为的能力——获取任意类的属性和方法、调用任意对象的方法、动态创建对象。
Object obj = getUnknownObject();
Method method = obj.getClass().getMethod("doSomething", null);
method.invoke(obj, null);反射机制核心流程:
获取类信息
Class<?> clazz = Class.forName("com.example.MyClass");
Method[] methods = clazz.getDeclaredMethods(); // 所有方法
Field[] fields = clazz.getDeclaredFields(); // 所有字段
Constructor<?>[] constructors = clazz.getConstructors(); // 构造函数典型应用场景
注解处理——JUnit 通过反射查找 @Test 方法:
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(Test.class)) {
method.invoke(testInstance);
}
}框架注入——Spring、Hibernate 用反射实现依赖注入和 ORM 映射。
序列化/反序列化——JSON/XML 库用反射获取对象属性进行转换。
动态代理——运行时生成代理类:
InvocationHandler handler = new MyInvocationHandler(target);
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class<?>[] { MyInterface.class },
handler
);访问私有成员
默认情况下反射无法访问私有成员,需调用 setAccessible(true):
Field privateField = clazz.getDeclaredField("secret");
privateField.setAccessible(true);
Object value = privateField.get(instance);注意
Java 9+ 模块系统限制:需要在 module-info.java 中使用 opens com.example to reflection; 开放包才能反射访问。
反射的代价与优化
| 代价 | 说明 |
|---|---|
| 性能 | 比直接调用慢 2-50 倍 |
| 安全限制 | 受安全管理器限制 |
| 可维护性 | 代码难以理解和调试 |
性能优化
使用 MethodHandle(Java 7+)、缓存 Method/Field 对象、或用字节码生成库(如 cglib)避免重复反射。
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
NoSuchMethodException | 方法名或参数类型不匹配 | 使用 getDeclaredMethod 并传入精确参数类型 |
IllegalAccessException | 未设置可访问 | 调用 setAccessible(true) |
InvocationTargetException | 被调用方法内部抛异常 | 通过 getTargetException() 获取真实异常 |
| Java 9+ 模块访问失败 | 模块系统限制 | module-info.java 中使用 opens 指令开放包 |