文章目录
- 482. Java 反射 - 访问私有方法 & 泛型擦除的影响
- 1. 访问私有方法 (Accessing Private Methods)
- 直接调用的问题
- 解决办法:`setAccessible(true)`
- 输出结果:
- 2. 泛型与类型擦除 (Generics and Type Erasure)
- 错误示例
- 正确示例
- 3. 总结
482. Java 反射 - 访问私有方法 & 泛型擦除的影响
1. 访问私有方法 (Accessing Private Methods)
直接调用的问题
如果你在类外部通过反射尝试调用一个private 方法,会抛出IllegalAccessException。
classUser{privatevoidsecret(){System.out.println("Top Secret!");}}User user = new User(); Method secretMethod = User.class.getDeclaredMethod("secret"); secretMethod.invoke(user); // ❌ 会抛 IllegalAccessException解决办法:setAccessible(true)
我们可以通过关闭访问检查来绕过限制:
secretMethod.setAccessible(true);// 关闭 Java 语言访问检查secretMethod.invoke(user);// ✅ 正常执行输出结果:
TopSecret!📌注意点:
setAccessible(true)只是关闭了访问控制检查,它不会改变方法的修饰符。- 在Java 模块系统(Java 9+)下,如果类属于其他模块,且模块没有开放包,调用可能依然会失败(需要
--add-opens)。
2. 泛型与类型擦除 (Generics and Type Erasure)
在 Java 中,泛型是编译期特性,运行时会发生类型擦除。
这意味着:反射看到的其实是擦除后的类型,而不是源代码中的泛型。
错误示例
List<String>strings=newArrayList<>();Class<?>clazz=strings.getClass();// ❌ 尝试获取 add(String) 方法MethodaddString=clazz.getMethod("add",String.class);运行结果:
Exceptionin thread"main"java.lang.NoSuchMethodException:java.util.ArrayList.add(java.lang.String)📌原因:
ArrayList<E>.add(E e)在运行时擦除为ArrayList.add(Object o)- 所以找不到参数是
String.class的方法
正确示例
List<String>strings=newArrayList<>();Class<?>clazz=strings.getClass();// ✅ 使用 Object.class 才能找到 add()MethodaddObject=clazz.getMethod("add",Object.class);addObject.invoke(strings,"Hello Reflection!");System.out.println(strings);输出结果:
[HelloReflection!]📌注意点:
- 反射操作是基于擦除后的类型,因此需要用
Object.class。 - 这样会失去泛型带来的类型安全(你甚至可以通过反射往
List<String>里塞一个Integer)。
3. 总结
- ✅私有方法
- 默认不可访问 → 需要
setAccessible(true) - 在模块化环境中可能需要
--add-opens
- 默认不可访问 → 需要
- ✅泛型与擦除
- 编译期有泛型,运行期被擦除
- 反射看到的参数类型通常是Object
- 使用反射会丢失泛型检查,可能破坏类型安全