Proxy.newProxyInstance 抛 IllegalArgumentException 因接口数组为 null、空或含非接口类;Object 方法会被代理并转发至 invoke;代理对象只能转接口不能转实现类;method.invoke 调用慢因反射开销大。

Proxy.newProxyInstance 为什么总抛 IllegalArgumentException
常见错误是传入的接口数组为 null、空数组,或里面混了非接口类(比如传了个 ArrayList.class)。JDK 要求必须全是 interface 类型,且不能重复。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 检查
interfaces参数是否用clazz.getInterfaces()直接拿——它可能返回空数组(比如类没实现任何接口) - 手动构造时别写
new Class[]{MyClass.class},得是new Class[]{MyInterface.class} - 如果目标类实现了多个接口,但只想代理其中一部分,必须显式列出,不能靠“继承关系”自动推导
InvocationHandler.invoke 的 method 参数为啥有时是 Object 的方法(toString/hashCode)
这是正常现象。JDK 代理对象在初始化、打印、比较时会调用 Object 的公共方法,它们也会被转发到 invoke。不处理这些方法,代理对象可能表现异常(比如 System.out.println(proxy) 打印出 null 或报错)。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 对
method.getDeclaringClass() == Object.class的情况,通常直接调用proxy.getClass().getName()或System.identityHashCode(proxy)做简单返回 - 不要无条件反射调用
method.invoke(target, args),target 可能是 null 或根本没实现toString - 如果用了 CGLIB 风格的“拦截所有方法”,这里就是第一个漏斗——JDK Proxy 天然只拦截接口方法,但
Object方法是特例
为什么代理对象不能强转成具体实现类,只能转接口
因为 Proxy.newProxyInstance 生成的是一个新类,它只实现你传入的 interfaces,和原始实现类没有继承关系。JVM 类型系统不允许向下转型。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 声明变量时就用接口类型:
MyService service = (MyService) Proxy.newProxyInstance(...),别试图(MyServiceImpl) - 如果业务代码里硬依赖实现类(比如反射取私有字段),说明设计已偏离接口抽象原则,Proxy 不是补丁工具
- 需要类似功能?考虑 CGLIB 或 ByteBuddy,但要注意它们生成的是子类,无法代理
final类或方法
InvocationHandler 里调用 method.invoke(target, args) 慢在哪
慢在反射本身:每次调用都要做访问检查、参数封装、类型匹配,尤其当 target 是普通对象(非 MethodHandle)时,JVM 很难内联优化。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 用
method.setAccessible(true)避免 SecurityManager 检查(开发/测试环境有效,生产需评估风险) - 高频场景下,缓存
MethodHandle:用MethodHandles.lookup().unreflect(method)替代反复反射调用 - 注意
target是否可能为null——比如你代理的是无状态接口,target根本不存在,这时invoke逻辑应完全自包含
InvocationHandler 当成万能钩子,却忘了它的每次触发都意味着一次明确的接口方法调用——不是事件,不是回调,更不是 AOP 的切入点。










