1. 程式人生 > >Java內部類之訪問許可權和編譯效率

Java內部類之訪問許可權和編譯效率

問題1: elementData的註釋的意思是,非私有化以簡化巢狀類的訪問,但巢狀類可以透明地訪問外圍類的所有成員,如何理解這裡的簡化?
為什麼不宣告為private呢?

通過檢視反編譯檢視位元組碼解決了問題:
虛擬機器不知道類的分組情況,會在類中提供非public方法供其他類訪問私有成員,也可用於封閉類。內部類在訪問外部類私有變數時,編譯器會為外部類新增一個非公有方法,內部類通過持有外部類的引用,呼叫此方法,訪問私有變數。

故宣告為非私有,可簡化編譯器新增非公有方法這個操作,提高效率。

如果安全允許且無封裝此物件的必要,使用private會加重編譯器的負擔。

1.內部類訪問外部非private
變數

public class Outer {
    public int i = 10;
    public class Inner {
        public int j = i;
    }
    public static void main(String[] args) throws InterruptedException {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        inner.j = 1;
    }
}

位元組碼如下
這裡寫圖片描述

逐句翻譯:

0:aload_0

將Slot 0的元素載入到操作棧(運算元0隱含在指令中)

1:invokespecial #10

呼叫父類Object的初始化方法

4:aload_0

將Slot 0的元素載入到操作棧

5:bitpush  10

將常量10載入到操作棧

7:putfeild  #12

訪問例項欄位i

10return

方法正常退出

main函式

0new #1

建立類Outer例項

3:dup

複製棧頂元素

4:invokespecial #23

呼叫Outer的初始化方法

7:astore_1

將棧頂元素存到區域性變量表Slot 1

8new #24

建立類Inner例項

11:dup

複製棧頂元素

12:aload_1

入棧

13:dup

複製棧頂元素

14:invokevirtual   #23

呼叫物件的例項方法getClass

17pop
18:invokespecial #30

呼叫Inner的初始化方法

21:astore_2

將棧頂元素存到區域性變量表Slot 2

22:aload_2
23:iconst_1
24:putfeild  #33

訪問例項欄位i

27return

方法退出

2.內部類訪問外部private變數

多了一個方法,編譯器自動給外部類Outer新增一個方法access$0,訪問私有變數i
這裡寫圖片描述

There is one more category of compiler-generated members. A private member m of a class C may be used by another class D, if one class encloses the other, or if they are enclosed by a common class. Since the virtual machine does not know about this sort of grouping, the compiler creates a local protocol of access methods in C to allow D to read, write, or call the member m. These methods have names of the form access0,access1, etc. They are never public. Access methods are unique in that they may be added to enclosing classes, not just inner classes.

虛擬機器不知道類的分組情況,會在類中提供非public方法供其他類訪問私有成員,也可用於封閉類。

看一下Inner的Class檔案
這裡寫圖片描述

內部類物件會產生名稱為this$0的一個欄位,該欄位儲存的是建立這個內部類物件的外部類物件引用,然後呼叫其access$0方法,為其私有變數i賦值