靈魂拷問:Java內(nèi)部類是如何訪問外部類私有對象的?
點擊上方 好好學(xué)java ,選擇 星標 公眾號
重磅資訊,干貨,第一時間送達 今日推薦:14 個 github 項目!
個人原創(chuàng)100W +訪問量博客:點擊前往,查看更多
我們都是知道內(nèi)部類就是寫在一個類里面的類,類里面的類,不知道你們有沒有看過javac之后的結(jié)果,就是將一個外部類編譯后,生成的字節(jié)碼文件結(jié)果
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;
}
}
}
這是我簡單手寫的一個外部類中嵌套一個內(nèi)部類。
當我編譯這段代碼javac OutClass.java

可以看出會生成兩個.class字節(jié)碼文件,內(nèi)部類的類名是外部類類名$內(nèi)部類類名
然后對這個兩個字節(jié)碼文件反編譯看看javap

可以看到,外部類OutClass除了默認構(gòu)造器和私有的屬性:name,id,address還多了三個靜態(tài)的方法,這三個方法不是我們手寫的。是編譯器自動生成的,什么作用呢。
不曉得?乛?乛?,然后看內(nèi)部類OutClass$innerClass ,發(fā)現(xiàn)編譯器也做了修改,首先,多了一個常量引用,final OutClass this$0 很明顯,這就是指向外部類的引用,有了引用怎么對他賦值呢,然后我們看到了那個構(gòu)造方法,我自己的源代碼中構(gòu)造方法的參數(shù)只有一個String innerName 而通過反編譯我看到了多了一個參數(shù),一個類型為OutClass,這就很明顯了嘛。
編譯器小哥偷偷的做了一些不可告人的事情,首先,內(nèi)部類中多了個常量引用,準備指向著外部類,而且又偷偷修改了構(gòu)造方法。傳遞一個OutClass類型的參數(shù)進去。這樣內(nèi)部類就拿到了外部類的引用。
但是僅僅拿到引用有個毛線用,通過反編譯可以看到,生成的是兩個字節(jié)碼文件,在虛擬機看來,這就是兩個不相關(guān)的類,你能在一個類中調(diào)用另外一個類的私有屬性嗎???
很明顯不能。這個時候我做了個方法的測試呀,我們都知道,內(nèi)部類使用外部類的屬性用過外部類類名.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);
}
然后我們通過反編譯看看這段代碼怎么執(zhí)行的。嘿嘿反編譯真是個好東西(●′?`●)4
javap -c OutClass$innerClass

看上去看不懂有點復(fù)雜,但是沒關(guān)系我們看右邊,看我紅色箭頭,是不是有點屬性,
Field this$0:LOutClass;
Method OutClass.access$000:(LOutClass;)Ljava/lang/String;
截取一部分,看見沒有,上面那個屬性是內(nèi)部類自動生成的常量指針,下面那個方法是外部類自動生成的三個靜態(tài)方法。將指向外部類的引用作為參數(shù)給那三個外部類中的靜態(tài)方法
然后我們?nèi)シ淳幾g看看那三個靜態(tài)方法怎么實現(xiàn)的
又是祭出偉大的反編譯工具

看得出,這三個方法都是返回外部類對應(yīng)的私有屬性!不過對于這點我還有點要說明,編譯器很智能,它會掃描內(nèi)部類,查看是否調(diào)用的外部類的私有屬性,只有調(diào)用了才會生成對應(yīng)的acess$xxx方法!
結(jié)論
在虛擬機中沒有外部類內(nèi)部類之分都是普通的類,但是編譯器會偷偷的做點修改,讓內(nèi)部類中多一個常量引用指向外部類,自動修改內(nèi)部類構(gòu)造器,初始化這個常量引用,而外部類通過掃描內(nèi)部類調(diào)用了外部類的那些私有屬性,為這些私有屬性創(chuàng)造acess$xxx靜態(tài)方法。這個方法是返回對應(yīng)的私有屬性的值。所以可以在一個類的外部獲取一個類的私有屬性的值
更多項目源碼
