
Method.invoke() 调用失败的常见报错和原因
直接调用 Method.invoke() 报 IllegalAccessException 或 IllegalArgumentException,基本是权限或参数没对齐。Java 反射默认不绕过访问控制,private 方法必须先 setAccessible(true);而参数类型不匹配(比如传了 int 却期望 Integer)会触发 IllegalArgumentException,哪怕看起来“值一样”。
- 静态方法调用时,
invoke()第一个参数传null,别传实例对象 - 原始类型参数必须用包装类或自动装箱,但要注意泛型擦除后
Object[]里放int会编译失败,得写new Object[]{Integer.valueOf(42)} - 如果目标方法抛异常,
invoke()会包一层InvocationTargetException,真实异常在getCause()里
getMethod() vs getDeclaredMethod() 到底选哪个
选错就找不到方法——getMethod() 只查 public 方法(含父类继承的),getDeclaredMethod() 查当前类声明的所有方法(含 private/protected,但不含继承的)。想调 private 工具方法?必须用 getDeclaredMethod(),再加 setAccessible(true)。
- 查构造器用
getDeclaredConstructor(),逻辑同理 - 方法重载时,参数类型必须精确匹配,
String.class和CharSequence.class不等价 - 数组类型参数要写
String[].class,不是String.class[]
反射调用的性能开销在哪,能不能缓存
慢主要在三块:查找方法(getMethod())、权限检查(setAccessible())、参数适配与封装。其中 getMethod() 最贵,重复调用同一方法时,务必把 Method 实例缓存起来复用。
-
setAccessible(true)在 JDK 9+ 有安全限制,模块化环境下可能被拒绝,需配置--add-opens - 缓存
Method对象本身是线程安全的,但别缓存调用结果(除非确定无副作用) - 高频调用场景(如 JSON 序列化框架),建议预热:首次调用前主动触发一次
setAccessible(true),避免运行时卡顿
泛型方法和可变参数的反射调用陷阱
泛型信息在运行时已擦除,所以 getGenericParameterTypes() 才能拿到原始泛型声明;而可变参数本质是数组,反射调用时得把 varargs 参数打包成一个数组对象传进去,否则会报参数个数不对。
立即学习“Java免费学习笔记(深入)”;
- 调用
void foo(String... args),应传new Object[]{new String[]{"a", "b"}},而不是new Object[]{"a", "b"} - 泛型返回值无法靠反射强制转型,
Method.getReturnType()返回的是擦除后的类型(如List而非List<string></string>) - 带注解的方法,用
getAnnotation()拿不到运行时注解(@Retention(RetentionPolicy.RUNTIME)才行)









