內部類是如何訪問外部類私有物件的
我們都是知道內部類就是寫在一個類裡面的類,類裡面的類,不知道你們有沒有看過javac之後的結果,就是將一個外部類編譯後,生成的位元組碼檔案結果
這是我簡單手寫的一個外部類中巢狀一個內部類。public class OutClass{ private String name; private int id; private String address; public class innerClass{ private String innerName; public void fun(){ System.out.println(OutClass.this.name+": "+innerName); System.out.println(OutClass.this.id+": "+innerName); System.out.println(OutClass.this.address+": "+innerName); } public innerClass(String innerName){ this.innerName = innerName; } } }
當我編譯這段程式碼javac OutClass.java
可以看出會生成兩個.class位元組碼檔案,內部類的類名是外部類類名$內部類類名
然後對這個兩個位元組碼檔案反編譯看看javap
可以看到,外部類OutClass除了預設構造器和私有的屬性:name,id,address還多了三個靜態的方法,這三個方法不是我們手寫的。是編譯器自動生成的,什麼作用呢。不曉得๑乛◡乛๑,然後看內部類OutClass$innerClass ,發現編譯器也做了修改,首先,多了一個常量引用,final OutClass this$0 很明顯,這就是指向外部類的引用,有了引用怎麼對他賦值呢,然後我們看到了那個構造方法,我自己的原始碼中構造方法的引數只有一個String innerName 而通過反編譯我看到了多了一個引數,一個型別為OutClass,這就很明顯了嘛,編譯器小哥偷偷的做了一些不可告人的事情,首先,內部類中多了個常量引用,準備指向著外部類,而且又偷偷修改了構造方法。傳遞一個OutClass型別的引數進去。這樣內部類就拿到了外部類的引用。
但是僅僅拿到引用有個毛線用,通過反編譯可以看到,生成的是兩個位元組碼檔案,在虛擬機器看來,這就是兩個不相關的類,你能在一個類中呼叫另外一個類的私有屬性嗎???
很明顯不能。這個時候我做了個方法的測試呀,我們都知道,內部類使用外部類的屬性用過外部類類名.this.屬性名,所以我寫了個測試方法fun
public void fun(){ System.out.println(OutClass.this.name+": "+innerName); System.out.println(OutClass.this.id+": "+innerName); System.out.println(OutClass.this.address+": "+innerName); }
然後我們通過反編譯看看這段程式碼怎麼執行的。嘿嘿反編譯真是個好東西(●´∀`●)4
javap -c OutClass$innerClass
看上去看不懂有點複雜,但是沒關係我們看右邊,看我紅色箭頭,是不是有點屬性,
Field this$0:LOutClass;
Method OutClass.access$000:(LOutClass;)Ljava/lang/String;
擷取一部分,看見沒有,上面那個屬性是內部類自動生成的常量指標,下面那個方法是外部類自動生成的三個靜態方法。將指向外部類的引用作為引數給那三個外部類中的靜態方法
然後我們去反編譯看看那三個靜態方法怎麼實現的
又是祭出偉大的反編譯工具
看得出,這三個方法都是返回外部類對應的私有屬性!不過對於這點我還有點要說明,編譯器很智慧,它會掃描內部類,檢視是否呼叫的外部類的私有屬性,只有呼叫了才會生成對應的acess$xxx方法!
結論:
在虛擬機器中沒有外部類內部類之分都是普通的類,但是編譯器會偷偷的做點修改,讓內部類中多一個常量引用指向外部類,自動修改內部類構造器,初始化這個常量引用,而外部類通過掃描內部類呼叫了外部類的那些私有屬性,為這些私有屬性創造acess$xxx靜態方法。這個方法是返回對應的私有屬性的值。所以可以在一個類的外部獲取一個類的私有屬性的值