跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何利用Java反射获取私有构造器并创建对象_权限突破与安全性讨论

必须用getDeclaredConstructor()获取私有构造器并调用setAccessible(true)才能创建实例;否则抛NoSuchMethodException或IllegalAccessException,Java 9+模块限制下还可能触发InaccessibleObjectException。 Java 反射调用私有构造器:
getDeclaredConstructor()
是唯一入口 想绕过访问控制创建私有构造的对象,必须用
getDeclaredConstructor()
,而不是
getConstructor()
—— 后者只查 public 构造器,私有的直接抛
NoSuchMethodException
。 关键点在于「declared」这个词:它表示本类声明的所有构造器,不管访问修饰符。但默认仍受 Java 访问检查限制,所以紧接着必须调用
setAccessible(true)
才能真正调用。
getConstructor()
查不到私有构造器,别白试
getDeclaredConstructor(Class...)
要传入精确参数类型,比如
String.class
,不能传实例值 如果构造器带泛型参数(如
List
),运行时已擦除,按原始类型写,即
List.class
多个重载私有构造器时,参数类型不匹配会抛
NoSuchMethodException
,不是
IllegalAccessException
调用前必须
setAccessible(true)
,否则
IllegalAccessException
逃不掉 即使拿到了
Constructor
对象,不设为可访问就 newInstance,JVM 会在运行时拦截并抛出
IllegalAccessException
。这不是异常处理能绕过的逻辑检查,是 SecurityManager(或模块系统)的硬性闸门。 注意:从 Java 9 开始,模块系统默认禁止对非开放包的反射访问,即使
setAccessible(true)
也可能失败,报
InaccessibleObjectException
—— 这时候得加 JVM 参数
--add-opens
或改模块配置。 立即学习 “ Java免费学习笔记(深入) ”; Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的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+ 默认)后,首次非法反射会警告,第二次直接报错 真正难处理的,是那些既没文档说明、又依赖隐式反射行为的第三方库——它们可能在某个小版本里悄悄改了构造逻辑,而你的反射调用就突然失效了。

相关文章