簡體   English   中英

java-11 之前的內部 class 訪問字段

[英]Inner class access field before java-11

有這樣的 class:

public class Sample1 {

    public class Inner {
        private int f;
    }

    void go() {
        Inner in = new Inner();
        int value = in.f;
    }

}

go方法(在 java-11 之前)的字節碼調用已知的合成方法:

static int access$000(nestmates.Sample1$Inner);
    descriptor: (Lnestmates/Sample1$Inner;)I
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #1                  // Field f:I
         4: ireturn

從:

0: new  #2  // class nestmates/Sample1$Inner
3: dup
4: aload_0
5: invokespecial #3 // Method nestmates/Sample1$Inner."<init>":(Lnestmates/Sample1;)V
8: astore_1
9: aload_1
10: invokestatic #4 // Method nestmates/Sample1$Inner.access$000:(Lnestmates/Sample1$Inner;)I

我知道這件事已經有一段時間了,但我從來沒有質疑過自己為什么會這樣? 為什么 javac 首先必須這樣做,為什么不直接通過 static 方法直接getField和這種間接尋址。 謝謝你。

因為 JVMS 不允許訪問不同 class 的私有成員,無論它是否是內部 class。 JDK 11 添加了nestmates的概念來克服這個限制。

原因是外部類和內部類編譯成不同的 class 文件,這意味着它們不能訪問彼此的私有成員。

生成合成方法是為了有效地擴大從私有到包私有的訪問,但它是通過不必要的間接方式實現的。

在 Java 11 中,他們為此引入了一個新概念,即允許不同文件中的類在某些情況下(即本例)訪問彼此的私有成員。

參見 JEP: https://openjdk.org/jeps/181

這是一個基於許多因素的簡單結論:

  1. 在 JVM(類文件java.exe )級別,內部類根本不存在。 完全沒有。 Javac 通過命名您的Inner class Sample1 Sample1$Inner來“偽造”它(那個美元不是渲染,那是它的實際 JVM 級別名稱, $ 只是一個符號,與In一樣有效),添加一個參數類型Sample1作為 Inner 的所有構造函數的第一個參數,將new Sample1()替換為new Sample1(this) ,將instanceOfOuter.new Sample1()替換為new Sample1(instanceOfOuter) ,具有Sample1類型的final字段(這些構造函數設置通過使用第一個參數),將所有對外部方法的調用轉換為在該字段上調用(假設在 JVM 級別沒有“外部 this”,因為沒有外部類),等等。 您可以使用javap -c查看所有這些。

  2. private成員不能被除自身之外的任何類型訪問,因此,假設內部 class 不再是編譯結束后的那個(因為 JVM 首先沒有內部 class 概念),它需要一個包 -私有(或受保護或公共,如您所願)的方式來獲取它。

  3. JVM也不知道合成意味着什么。 這是一個標志,是的,JVM 完全忽略了。 它不知道它意味着什么,它根本不影響代碼的運行或解釋方式 javac知道合成的意思。 即:標記任何你編寫的東西,將精心管理的偽造物粘合在一起,使內部類看起來像是純粹的 java 語言(即編譯器)功能並且不存在於 java 運行時級別- 並且在閱讀 class 文件時,對它們視而不見。 就像這些合成方法不存在一樣。 比如,如果 javac 被要求編譯試圖調用合成方法的代碼,那么就像編譯試圖調用不存在的方法的代碼一樣。

正如評論已經指出的那樣,java 的更新版本確實在 JVM 級別引入了內部類的概念,但並不是通過在 JVM 規范中體現“內部類”的概念,而是通過具有“同胞”概念,這讓 class 文件列出其他 class 名稱,這些名稱可以“查看”並調用/與私有元素交互。 現代 javacs,如果以現代 JVM 為目標(這里的“現代”定義為:“具有可用的 nestmates 功能”),將使用 nestmates 並放棄所有合成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM