一、反射调用方法核心步骤
1. 获取Class对象
Class<?> clazz = TargetClass.class; // 或 Class.forName("全类名")
2. 定位目标方法
// 方法名 + 参数类型列表
Method method = clazz.getDeclaredMethod("methodName", String.class, int.class);
3. 突破访问限制(可选)
method.setAccessible(true); // 调用私有方法必备
4. 执行方法调用
Object result = method.invoke(targetInstance, "参数1", 100); // 静态方法时targetInstance为null
二、深度原理剖析
- invoke()底层机制
JVM通过MethodAccessor接口实现动态调用,首次调用生成字节码增强的NativeMethodAccessorImpl,后续调用直接跳转避免JNI开销。 - 可变参数处理
invoke()接收Object... args,自动装箱基本类型并验证参数数量与类型匹配,不匹配则抛出IllegalArgumentException。 - 多态行为保留
反射调用遵循Java多态规则,实际执行对象重写后的方法:
class Parent { void show() { System.out.println("Parent"); } }
class Child extends Parent { void show() { System.out.println("Child"); } }
Parent obj = new Child();
Method m = Parent.class.getDeclaredMethod("show");
m.invoke(obj); // 输出"Child" ✅
三、实战代码示例
示例1:暴力调用私有方法
public class SecretService {
private String revealSecret() { return "Confidential Data"; }
}
public static void main(String[] args) throws Exception {
SecretService service = new SecretService();
Method method = SecretService.class.getDeclaredMethod("revealSecret");
method.setAccessible(true); // 关键!解除私有封印
String secret = (String) method.invoke(service);
System.out.println("窃取机密: " + secret); // 输出: Confidential Data
}
示例2:动态代理实现AOP日志
interface UserService { void saveUser(String name); }
class UserServiceImpl implements UserService {
public void saveUser(String name) { System.out.println("保存用户: " + name); }
}
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class[]{UserService.class},
(p, method, params) -> {
System.out.println("▶️ 方法调用: " + method.getName() + " 参数: " + Arrays.toString(params));
return method.invoke(target, params);
}
);
proxy.saveUser("Alice"); // 自动打印调用日志
}
四、性能与安全警示
- 性能黑洞
反射调用比直接调用慢 20-50倍!高频场景务必缓存Method对象或考虑MethodHandle。 - 安全红线
· 开放setAccessible(true)可能导致私有API被恶意调用
· 规避方案:启用安全管理器(SecurityManager)
结语
反射方法调用是框架设计的基石(如Spring IoC),但日常开发需克制使用。掌握其原理与风险,方能在灵活性与稳定性间取得平衡。示例代码已托管至GitHub仓库。
关键选择建议:
· 框架开发 → 拥抱反射
· 业务代码 → 优先接口与设计模式
· 性能瓶颈 → 尝试MethodHandle或字节码增强(如ASM)
666

被折叠的 条评论
为什么被折叠?



