java11新特性—基于嵌套的访问控制

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);
    // JDK 11 之前,如下代码报出异常:IllegalAccessException
    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);
    // JDK 11 之后,如下代码不会出现异常
    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();
}
}