必须用getDeclaredConstructor()获取私有构造器并调用setAccessible(true)才能创建实例;否则抛NoSuchMethodException或IllegalAccessException,Java 9+模块限制下还可能触发InaccessibleObjectException。

Java 反射调用私有构造器:getDeclaredConstructor() 是唯一入口
想绕过访问控制创建私有构造的对象,必须用 getDeclaredConstructor(),而不是 getConstructor() —— 后者只查 public 构造器,私有的直接抛 NoSuchMethodException。
关键点在于「declared」这个词:它表示本类声明的所有构造器,不管访问修饰符。但默认仍受 Java 访问检查限制,所以紧接着必须调用 setAccessible(true) 才能真正调用。
-
getConstructor()查不到私有构造器,别白试 -
getDeclaredConstructor(Class...)要传入精确参数类型,比如String.class,不能传实例值 - 如果构造器带泛型参数(如
List<string></string>),运行时已擦除,按原始类型写,即List.class - 多个重载私有构造器时,参数类型不匹配会抛
NoSuchMethodException,不是IllegalAccessException
调用前必须 setAccessible(true),否则 IllegalAccessException 逃不掉
即使拿到了 Constructor 对象,不设为可访问就 newInstance,JVM 会在运行时拦截并抛出 IllegalAccessException。这不是异常处理能绕过的逻辑检查,是 SecurityManager(或模块系统)的硬性闸门。
注意:从 Java 9 开始,模块系统默认禁止对非开放包的反射访问,即使 setAccessible(true) 也可能失败,报 InaccessibleObjectException —— 这时候得加 JVM 参数 --add-opens 或改模块配置。
立即学习“Java免费学习笔记(深入)”;
-
setAccessible(true)必须在newInstance()前调用,顺序错等于没开锁 - 该调用本身可能抛
SecurityException(如有安全管理器且策略拒绝) - Java 12+ 在某些安全敏感上下文中(如某些容器、Android ART)会静默忽略
setAccessible(true),实际仍不可访问
常见误用场景:反序列化、Mock 框架、单元测试中的陷阱
很多框架(如 Mockito、Jackson 默认反序列化器)内部也靠反射调私有构造器,但它们都做了容错封装。你自己手写时容易漏掉边界条件。
比如:构造器抛异常、含 final 字段未初始化、依赖外部状态(如静态字段未 setup)、或对象创建后未触发必要的初始化逻辑(如 @PostConstruct 方法不会自动执行)。
- 构造器抛
RuntimeException会原样抛出,不是包装成InvocationTargetException—— 注意捕获类型 - 若类含
private static final字段且依赖构造器外赋值(如静态块),反射创建对象时这些字段仍是默认值(null/0) - Spring 的
@Autowired字段不会自动注入,反射创建的是“裸对象”,和容器托管生命周期无关 - Android 上 Dalvik/ART 对反射限制更严,
setAccessible(true)在高版本可能直接被拒,无替代 API
安全性不是幻觉:setAccessible(true) 不等于“绕过安全模型”
很多人以为开了反射权限就等于彻底突破安全边界,其实不是。它只是跳过了 Java 语言层的访问检查,底层仍受 JVM 安全机制约束。比如:
- 如果类被加载进受限模块(
java.base等系统模块),即使setAccessible(true)也会被模块系统拦截 - SecurityManager 若启用,会调用
checkPermission(new ReflectPermission("suppressAccessChecks")),拒绝则抛SecurityException - 某些 JDK 发行版(如 Alibaba Dragonwell、某些银行定制版)默认禁用反射权限,且无法通过参数打开
- 生产环境开启
--illegal-access=deny(Java 16+ 默认)后,首次非法反射会警告,第二次直接报错
真正难处理的,是那些既没文档说明、又依赖隐式反射行为的第三方库——它们可能在某个小版本里悄悄改了构造逻辑,而你的反射调用就突然失效了。


















