482. Java 反射 - 访问私有方法 & 泛型擦除的影响

482. Java 反射 - 访问私有方法 & 泛型擦除的影响


1. 访问私有方法 (Accessing Private Methods)

直接调用的问题

如果你在类外部通过反射尝试调用一个 private 方法,会抛出 IllegalAccessException

class User {
    private void secret() {
        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);         // ✅ 正常执行

输出结果:

Top Secret!

📌 注意点

  • setAccessible(true) 只是关闭了 访问控制检查,它 不会改变方法的修饰符
  • Java 模块系统(Java 9+) 下,如果类属于其他模块,且模块没有开放包,调用可能依然会失败(需要 --add-opens)。

2. 泛型与类型擦除 (Generics and Type Erasure)

在 Java 中,泛型是 编译期特性,运行时会发生 类型擦除
这意味着:反射看到的其实是擦除后的类型,而不是源代码中的泛型。


错误示例

List<String> strings = new ArrayList<>();
Class<?> clazz = strings.getClass();

// ❌ 尝试获取 add(String) 方法
Method addString = clazz.getMethod("add", String.class);

运行结果:

Exception in 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 = new ArrayList<>();
Class<?> clazz = strings.getClass();

// ✅ 使用 Object.class 才能找到 add()
Method addObject = clazz.getMethod("add", Object.class);
addObject.invoke(strings, "Hello Reflection!");

System.out.println(strings);

输出结果:

[Hello Reflection!]

📌 注意点

  • 反射操作是 基于擦除后的类型,因此需要用 Object.class
  • 这样会失去泛型带来的 类型安全(你甚至可以通过反射往 List<String> 里塞一个 Integer)。

3. 总结

  • 私有方法
    • 默认不可访问 → 需要 setAccessible(true)
    • 在模块化环境中可能需要 --add-opens
  • 泛型与擦除
    • 编译期有泛型,运行期被擦除
    • 反射看到的参数类型通常是 Object
    • 使用反射会丢失泛型检查,可能破坏类型安全
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容