从Java 9开始,JDK引入了模块系统(Module System),对核心类库中的内部API进行了强封装。过去通过反射访问sun.misc.Unsafe或java.lang.invoke包中非导出成员的做法,在新版本中会受到限制。JVM提供了--illegal-access参数来控制这种反射访问的行为,其中deny模式会直接拒绝所有非法访问。

什么是--illegal-access参数
--illegal-access是Java 9引入的JVM启动参数,用于管理代码对强封装模块内部成员的反射访问。它有四个可选值:
- permit:默认行为(Java 9至16),仅对第一个非法访问给出警告,后续静默允许。
- warn:每次非法访问都输出警告。
- debug:输出警告并附带堆栈跟踪。
- deny:拒绝任何非法反射访问,抛出异常。
在Java 17及以后,--illegal-access默认等同于deny,且该参数已被标记为废弃,但显式书写仍可明确意图。
为什么应使用deny模式
强封装的目的是让JDK内部实现可以自由演进,而不破坏外部依赖。如果程序依赖内部变量或方法,一旦JDK升级就可能崩溃。使用--illegal-access=deny能提前暴露问题,迫使开发者改用标准API或采用命令行开放模块。
典型错误示例
以下代码尝试读取java.base模块中未导出的字段:
import java.lang.reflect.Field;
public class IllegalAccessDemo {
public static void main(String[] args) throws Exception {
// 试图访问 String 的内部 value 字段(Java 9+ 已强封装)
Field field = String.class.getDeclaredField("value");
field.setAccessible(true); // 此处触发非法访问
char[] value = (char[]) field.get("test");
System.out.println(value);
}
}
在deny模式下运行会得到InaccessibleObjectException,而不是悄悄成功。
如何配置--illegal-access=deny
命令行直接启动
java --illegal-access=deny -jar myapp.jar
Maven中配置
在pom.xml的编译器插件或执行配置中加入参数:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--illegal-access=deny</argLine>
</configuration>
</plugin>
临时开放特定模块
若必须访问内部API且无法立即修改代码,可用--add-opens在启动期开放包:
java --illegal-access=deny --add-opens java.base/java.lang=ALL-UNNAMED -jar myapp.jar
迁移建议
| 场景 | 推荐做法 |
|---|---|
| 使用内部集合API | 改用java.util标准集合 |
| 依赖Unsafe特定方法 | 评估VarHandle或Foreign Function接口 |
| 第三方库触发警告 | 升级库版本或提交issue |
将--illegal-access设为deny不仅是应对JDK演进的策略,也是编写健壮Java应用的良好习惯。尽早消除对内部API的依赖,可显著降低升级风险。
JVMillegal-accessmodule_system修改时间:2026-07-27 04:03:19