Java中可通过反射调用private构造函数:先用getDeclaredConstructor()获取,再setAccessible(true)启用访问,最后newInstance()或construct()创建实例;但破坏封装性,JDK9+需注意模块限制与InaccessibleObjectException。

Java 中 private 构造方法可以通过反射绕过访问控制,调用 setAccessible(true) 后直接实例化对象。关键在于:必须先获取构造器对象,再解除访问限制,最后用 newInstance()(旧版)或 construct()(新版推荐)创建实例。
获取 private 构造器
使用 getDeclaredConstructor(...) 而非 getConstructor(...),因为后者只返回 public 构造器。需显式传入参数类型数组,匹配目标构造方法签名。
- 若无参:用
getDeclaredConstructor() - 若有参:如
String.class, int.class,顺序和类型必须完全一致 - 若类有多个 private 构造器,需逐一判断参数类型来选择
调用 setAccessible(true)
这是关键一步——setAccessible(true) 会临时关闭 Java 的访问检查机制(依赖于 SecurityManager 是否允许)。JDK 9+ 默认开启模块系统,可能需在运行时添加 --add-opens 参数(如 --add-opens java.base/java.lang=ALL-UNNAMED),否则会抛 InaccessibleObjectException。
- 该操作仅影响当前
Constructor实例,不改变类定义 - 多次调用
setAccessible(true)无副作用,但不能对已释放的构造器重复操作
创建实例
调用 newInstance(...)(JDK 9 起标记为 deprecated)或更安全的 newInstance(...) 替代方案:construct(...)(JDK 14+ 推荐);实际开发中建议统一用 newInstance(...) 并捕获异常。
立即学习“Java免费学习笔记(深入)”;
- 传入的实参类型和数量必须与构造器声明严格匹配
- 若构造器抛出 checked exception,反射调用会包装为
InvocationTargetException,需检查其getCause() - 若构造器内部抛出 RuntimeException,会原样抛出
注意事项与常见问题
反射调用 private 构造器虽可行,但存在隐性风险:破坏封装、绕过单例/初始化逻辑、触发 JVM 安全限制。
- 单例类通常用 enum 或静态 holder 模式,反射可破,但属于设计层面妥协
- JDK 17+ 默认强封装模块,未显式开放的包内 private 成员无法通过反射访问
- Android 上部分版本限制更严,
setAccessible可能被忽略或抛 SecurityException


















