嵌套是一种访问控制上下文,它容许多个class同属一个逻辑代码块,可是被编译成多个分散的class文件,它们访问彼此的私有成员无需经过编译器添加访问扩展方法。java
不少jvm语言支持在一个源文件中放多个class。这对于用户是透明的,用户认为它们在一个class中,因此但愿它们共享同一套访问控制体系。为了达到目的,编译器须要常常须要经过附加的access bridge扩大private成员的访问权限到package。这种bridge和封装相违背,而且轻微的增长程序的大小,会干扰用户和工具。因此咱们但愿一种更直接,更安全,更透明的方式。安全
一个更大的坑就是反射的时候会有问题。当使用java.lang.reflect.Method.invoke从一个nestmate调用另外一个nestmate私有方法时会报IllegalAccessError错误。这个是让人不能理解的,由于反射应该和源码级访问拥有相同权限。jvm
话很少说,看段代码
工具
public class JEP181 {
public static class Nest1 {
private int varNest1;
public void f() throws Exception {
final Nest2 nest2 = new Nest2();
//这里没问题
nest2.varNest2 = 2;
final Field f2 = Nest2.class.getDeclaredField("varNest2");
//这里在java8环境下会报错,在java11中是没问题的
f2.setInt(nest2, 2);
System.out.println(nest2.varNest2);
}
}
public static class Nest2 {
private int varNest2;
}
public static void main(String[] args) throws Exception {
new Nest1().f();
}
}
复制代码
为了提供一种更大的,更普遍的,不单单是java语言的嵌套类型,而且补足访问控制检测的不足,引入了两个新的class文件属性。定义了两种nest member,一种叫nest host(也叫top-level class),它包含一个NestMembers属性用于肯定其余静态的nest members,其余的就是nest member,它包含一个NestHost属性用于肯定它的nest host。spa
你们能够看一下上述代码的class文件详情。翻译
调整了jvm访问规则,增长了以下条款:
一个field或method R能够被class或interface D访问,当且仅当以下任一条件为真:code
C和D是nestmates表名他们确定有一个相同的hostci
这个松散的访问规则会做用在以下几个地方:(这一段我就贴原文了,感受翻译过来味道就变了)get
针对上述访问规则的改变,相应的调整字节码:编译器
嵌套类必须在访问前校验。校验最迟要发生在访问成员以前,最先能够发生在对class文件的校验时,或者在二者之间,好比JIT时。校验嵌套关系,须要加载nest host类,为了防止无心义的加载,这一步尽可能放到最后作。
为了保证嵌套的完整性,建议禁止修改nest classfile属性