java11新特性---Nest-Based Access Control(嵌套訪問控制)

簡介

嵌套是一種訪問控制上下文,它容許多個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();
    }
}
複製代碼
在java11以前,classfile用InnerClasses和EnclosingMethod兩種屬性來幫助編譯器確認源碼的嵌套關係,每個嵌套的類型會編譯到本身的class文件中,在使用上述屬性來鏈接其餘class文件。這些屬性對於jvm肯定嵌套關係上已經足夠了,可是它們不直接適用於訪問控制,而且和java語言綁定的太緊了。

爲了提供一種更大的,更普遍的,不單單是java語言的嵌套類型,而且補足訪問控制檢測的不足,引入了兩個新的class文件屬性。定義了兩種nest member,一種叫nest host(也叫top-level class),它包含一個NestMembers屬性用於肯定其餘靜態的nest members,其餘的就是nest member,它包含一個NestHost屬性用於肯定它的nest host。spa

你們能夠看一下上述代碼的class文件詳情。翻譯

JVM針對嵌套成員的訪問控制

調整了jvm訪問規則,增長了以下條款:
一個field或method R能夠被class或interface D訪問,當且僅當以下任一條件爲真:code

  • … …(原條款不變)
  • R是私有的,而且聲明在另外一個class或interface C中,而且C和D是nestmates

C和D是nestmates表名他們確定有一個相同的hostci

這個鬆散的訪問規則會做用在以下幾個地方:(這一段我就貼原文了,感受翻譯過來味道就變了)get

  • Resolving fields and methods (JVMS 5.4.3.2, etc.)
  • Resolving method handle constants (JVMS 5.4.3.5)
  • Resolving call site specifiers (JVMS 5.4.3.6)
  • Checking Java language access by instances of java.lang.reflect.AccessibleObject
  • Checking access during queries to java.lang.invoke.MethodHandles.Lookup

針對上述訪問規則的改變,相應的調整字節碼:編譯器

  • invokespecial for private nestmate constructors,
  • invokevirtual for private non-interface, nestmate instance methods,
  • invokeinterface for private interface, nestmate instance methods; and
  • invokestatic for private nestmate, static methods

嵌套類的校驗

嵌套類必須在訪問前校驗。校驗最遲要發生在訪問成員以前,最先能夠發生在對class文件的校驗時,或者在二者之間,好比JIT時。校驗嵌套關係,須要加載nest host類,爲了防止無心義的加載,這一步儘可能放到最後作。

爲了保證嵌套的完整性,建議禁止修改nest classfile屬性

相關文章
相關標籤/搜索