嵌套是一種訪問控制上下文,它容許多個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屬性