JDK11 开始在 public 、protected 、private 的基础上,JVM 又提供了一种新的访问机制:Nest
在一个类中嵌套了多个类,各类中可以直接访问彼此的私有成员
jdk11之前
class Outer { private int outerInt; class Inner { public void test() { System.out.println("Outer int = " + outerInt); } } }
|
编译后
class Outer { private int outerInt; public int access$000() { return outerInt; } } class Inner$Outer { Outer outer; public void test() { System.out.println("Outer int = " + outer.access$000()); } }
|
以上方案虽然从逻辑上讲,内部类是与外部类相同的代码实体的一部分,但它被编译为一个单独的类。因此,它需要编译器创建合成桥接方法,以提供对外部类的私有字段的访问。
这种方案一个很大的坑是反射的时候会有问题。
当使用反射在内部类中访问外部类的私有成员 outerInt 时会报 IllegalAccessError 错误。这个是让人不能理解的,因为反射还是源码级访问的权限
class Outer { private int outerInt; class Inner { public void test() throws Exception { System.out.println("Outer int = " + outerInt); Class c = Outer.class ; Field f = c.getDeclaredField("outerInt"); f.set(Outer.this, 23); } } public static void main(String[] args) throws Exception { new Outer().new Inner().test(); } }
|
jdk11
JDK11 开始,嵌套是一种访问控制上下文,它允许多个 class 同属一个逻辑代码块,但是被编译成多个分散的 class 文件,它们访问彼此的私有成员无需通过编译器添加访问扩展方法,而是可以直接进行访问,如果上述代码可以直接通过反射访问外部类的私有成员,而不会出现权限问题
class Outer { private int outerInt; class Inner { public void test() throws Exception { System.out.println("Outer int = " + outerInt); Class c = Outer.class ; Field f = c.getDeclaredField("outerInt"); f.set(Outer.this, 23); } } public static void main(String[] args) throws Exception { new Outer().new Inner().test(); } }
|