java 9+ 中 setaccessible(true) 因 jpms 模块封装限制抛 inaccessibleobjectexception,需用 --add-opens java.base/java.lang=all-unnamed 等 jvm 参数显式授权,格式严格、大小写敏感、运行时生效。

Java 9+ 引入 JPMS 后,setAccessible(true) 不再能绕过模块封装限制,反射访问私有成员(字段、方法、注解等)会直接抛 InaccessibleObjectException。这不是代码写错了,而是 JVM 在模块边界上主动拦截——必须通过 --add-opens 显式授权才能通行。
看异常信息,精准定位要开放的模块和包
异常堆栈里一定包含关键线索,例如:
Unable to make field private final java.lang.String java.lang.String.value accessible: module java.base does not "opens java.lang" to unnamed module从中提取三要素:
-
源模块名:
java.base(异常中 “module java.base”) -
目标包名:
java.lang(引号中 “opens java.lang”) -
调用方身份:
unnamed module(即类路径启动的应用,默认叫 unnamed module)
对应参数就是:--add-opens java.base/java.lang=ALL-UNNAMED
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
正确写法:格式不能错,粒度不能粗
--add-opens 必须严格按 源模块/包=目标模块 格式书写,常见错误包括:
- 漏写包名(如
--add-opens java.base=ALL-UNNAMED→ 无效) - 写错包路径(如
java.lang.String是类,真正要开的是java.lang包) - 误用通配符或合并写法(如
--add-opens java.base/*=ALL-UNNAMED或多包合并在一条里 → 不支持) - 把
ALL-UNNAMED写成all-unnamed(大小写敏感,必须全大写)
多个包需要开放?逐条写:
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED
运行时加,不是编译时加
--add-opens 是 JVM 启动参数,只在启动时生效:
- IDE 中(如 IntelliJ):在 Run/Debug Configurations → VM options 里填写,不要放在 Program arguments 或其他位置
-
Maven:用
maven-surefire-plugin的<jvmarguments></jvmarguments>配置测试,或maven-failsafe-plugin同理;主应用需配合exec:java或外部脚本 -
打包后运行:在
java -jar命令前加上参数,例如:java --add-opens java.base/java.lang=ALL-UNNAMED -jar app.jar
如果用了命名模块,建议用模块名代替 ALL-UNNAMED
如果你的项目已声明 module-info.java(比如 module com.example.app),更安全的做法是:
- 把
ALL-UNNAMED换成你自己的模块名:--add-opens java.base/java.lang=com.example.app - 这样避免意外影响其他 unnamed 模块,也符合模块系统的设计意图
- 若反射调用方是第三方库模块(如
com.fasterxml.jackson.databind),也要对应写成该模块名
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










