JDK9之后限制了反射方式对于JDK内部类的访问,因此在使用高版本JDK运行较低版本的JDK时,某些依赖由于会发生错误。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class SimpleClass {
private String foo = "foo";
public String getFoo() {
return foo;
}
}

public class Main {
// 反射访问和修改非JDK内部类SimpleClass
public static class ReflectSimpleClass {
private void changeFoo(SimpleClass simpleClass) {
try {
Field fooField = SimpleClass.class.getDeclaredField("foo");
fooField.setAccessible(true);
fooField.set(simpleClass, "bar");
} catch (NoSuchFieldException | IllegalAccessException e) {
System.out.println(e.getMessage());
}
}
}
// 反射访问和修改JDK内部类ArrayList
public static class ReflectInternalClass {
private<T> void changeSize(ArrayList<T> arrayList) {
try {
Field sizeField = ArrayList.class.getDeclaredField("size");
sizeField.setAccessible(true);
sizeField.set(arrayList, 114514);
} catch (NoSuchFieldException | IllegalAccessException e) {
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args) {
// 分别测试对JDK内部类和非JDK内部类的反射访问和修改,从JDK16开始,修改JDK内部类的属性则会报错
// 测试结果:若JDK版本是8,可以修改JDK内部类的属性;若JDK版本是17,则不行。
// IDEA修改运行时的JDK版本的方法:Main->Edit Configuration->Build and Run
SimpleClass simpleClass = new SimpleClass();
System.out.println(simpleClass.getFoo());
new ReflectSimpleClass().changeFoo(simpleClass);
// 预期输出:bar
System.out.println(simpleClass.getFoo());
// 测试对JDK内部类的反射访问和修改
ArrayList<Integer> arrayList = new ArrayList();
System.out.println(arrayList.size());
new ReflectInternalClass().changeSize(arrayList);
// 预期输出:114514,JDK版本为17会报错
System.out.println(arrayList.size());
}
}

解决方案

从 JDK 9 开始,引入了模块化系统(Project Jigsaw),限制了对 JDK 内部类的反射访问。为了在高版本 JDK 中通过反射访问 JDK 内部类,可以通过添加 JVM 参数来开放模块对所需方法的访问权限。

具体操作:

在 IntelliJ IDEA 中:

  1. 打开 Edit Configuration

  2. VM options 中添加以下参数:

    1
    --add-opens java.base/java.lang=ALL-UNNAMED

参数说明:

  • --add-opens:用于开放模块的访问权限。
  • java.base/java.lang:指定模块和包路径。
  • ALL-UNNAMED:允许所有未命名模块访问。

__END__