成員內部類可以繼承其他的類,也可以被其它類繼承,本文主要說明其它類繼承成員內部類的問題。
本文要點如下:
1).成員內部類的子類可以是內部類,也可以不是內部類;
2).當成員內部類的子類不是內部類或子類雖是內部類但與其父類不在同一個外部類時,子類的構造方法第一句要顯式添加如下的語句:
外部類對象引用.super(參數);
這里的外部類指父類所在的外部類;
3).編譯器默認給成員內部類的構造方法傳入一個參數,該參數是內部類所依附的外部類對象的引用;
注:本文涉及到的類都是非靜態類。
作者: 蟬蟬
請尊重作者勞動成果,轉載請在標題注明“轉載”字樣,並標明原文鏈接:
http://www.cnblogs.com/chanchan/p/8345144.html
參考資料:
http://www.cnblogs.com/dolphin0520/p/3811445.html
背景知識點:
1).內部類是如何依附於外部類的?
編譯器編譯時,是把外部類與成員內部類編譯成兩個獨立的文件的;
但會給成員內部類默認添加一個類型為外部類對象引用的成員變量,並為構造方法默認傳入一個類型為外部類對象引用的參數,並以該參數值來初始化該成員變量;
如下所示:
final Person this$0;
InnerClass(Person per){
...
this$0 = per;
...
}
也就是說,成員內部類的對象保存了一個外部類對象的引用,通過這個引用,內部類就可以無限制的訪問外部類的成員了。
從這里也可以看出,創建成員內部類對象之前必須要存在一個外部類對象,即,成員內部類是依附於外部類的。
2).創建子類對象時,要先調用父類構造方法再調用子類構造方法。
詳細參見筆記11。
3).子類構造方法中如果沒有顯式調用super(參數),則會在構造方法最前面默認添加super();。
下面分三種情況來討論:
1.子類是內部類且與父類位於同一個外部類
外部類是Person,父類是成員內部類InnerClassParent,子類是成員內部類InnerClassChild。
1 //筆記22--成員內部類--父類 2 class InnerClassParent { 3 InnerClassParent (){ 4 System.out.println("內部類--父類"); 5 } 6 } 7 8 //筆記22-成員內部類--子類 9 class InnerClassChild extends InnerClassParent { 10 InnerClassChild(){ 11 System.out.println("內部類的子類是內部類且位於同一外部類"); 12 } 13 } 14 15 public static void main(String[] args) { 16 Person per22 = new Person(); 17 InnerClassChild inCCh = per22.new InnerClassChild(); 18 }
輸出結果為:
內部類--父類
內部類的子類是內部類且位於同一外部類
分析:
1).由背景知識點1)可知,編譯后,
子類實際的樣子大概是如下這樣的:
1 //筆記22-成員內部類--子類 2 class InnerClassChild extends InnerClassParent { 3 final Person this$0; 4 5 InnerClassChildIn(Person per){ 6 super(); 7 this$0 = per; 8 System.out.println("內部類的子類是內部類且位於同一外部類"); 9 } 10 }
父類實際的樣子大概是如下這樣的:
1 //筆記22--成員內部類--父類 2 class InnerClassParent { 3 final Person this$0; 4 InnerClassParent(Person per){ 5 this$0 = per; 6 System.out.println("內部類--父類"); 7 } 8 }
2).根據上面的分析,作出執行的流程圖,如下所示:
1>.先創建外部類對象per,再通過per來創建其成員內部類InnerClassChild(子類);
2>.要創建子類對象,必須先加載父類再加載子類(這里子類、父類都是初次使用,尚未加載),然后初始化父類成員並調用父類構造方法,最后再初始化子類成員並調用子類的構造方法;
3>調用完子類構造方法后,子類對象inCCh創建完成;
3).子類對象inCCh創建后的內存結構圖如下所示:
子類對象創建完成后,子類與父類都有一個外部類對象引用this$0,且都指向了per。
相關知識點:
1>.堆、棧,參見筆記把大端、小端與堆、棧的生長方向聯系起來記憶
2>.隱藏與覆蓋,參見筆記12
2.子類是內部類且與父類位於不同的外部類
外部類DustMan的成員內部類是InnerClassChildDM,InnerClassChildDM繼承了外部類Person的成員內部類InnerClassParent。
子類InnerClassChildDM的代碼如下:
1 //筆記22--成員內部類--子類為內部類且不在同一個外部類 2 class InnerClassChildDM extends Person.InnerClassParent { 3 InnerClassChildDM(Person per){ 4 per.super(); 5 System.out.println("成員內部類的子類為內部類且與父類不在同一個外部類"); 6 } 7 } 8 public static void main(String[] args) { 9 DustMan du = new DustMan(); 10 Person per = new Person(); 11 InnerClassChildDM inCChDM = du.new InnerClassChildDM(per); 12 }
輸出結果如下:
內部類--父類
成員內部類的子類為內部類且與父類不在同一個外部類
分析:
1).編譯后,子類的實際樣子大概是下面這樣的:
1 //筆記22--成員內部類--子類為內部類且不在同一個外部類 2 class InnerClassChildDM extends Person.InnerClassParent { 3 final DustMan this$0; 4 InnerClassChildDM(DustMan du, Person per){ 5 per.super(); 6 this$0 = du; 7 System.out.println("成員內部類的子類為內部類且與父類不在同一個外部類"); 8 } 9 }
2).與第一種情況不同的是,子類InnerClassChildDM中顯式添加了per.super();
這是因為,子類與父類處於不同的外部類,編譯時,子類的構造方法默認傳入的是DustMan類的對象引用,而不是Person類的對象引用;
如果要調用父類的構造方法的話,必須要給它傳入一個其外部類Person的對象引用;
所以這時,子類的構造方法顯式傳入一個Person類對象引用per,並通過per.super();的方式把per傳給父類的構造方法並調用之。
3).執行的流程圖如下所示:
4).子類對象inCChDM創建完成后的內存分配圖如下:
其中,子類的this$0是指向DustMan類的對象du的,父類的this$0是指向Person類的對象per的。
3.子類不是內部類
InnerClassChild不是內部類,它繼承了外部類Person的成員內部類InnerClassParent。
1 package human; 2 3 public class InnerClassChild extends Person.InnerClassParent { 4 InnerClassChild(Person per) { 5 per.super(); 6 System.out.println("內部類的子類不是內部類"); 7 } 8 9 public static void main( String[] args ) { 10 Person per = new Person(); 11 InnerClassChild inCCh = new InnerClassChild(per); 12 } 13 }
輸出結果如下:
內部類--父類
內部類的子類不是內部類
分析:
1).子類不是內部類,所以編譯器不會在其構造方法中傳入其外部類的對象引用。
2).子類的構造方法也顯式的添加了per.super();語句,原因同上。
3).執行的流程圖如下所示:
4).子類對象inCChNoI創建完成后,內存分配圖如下:
其中,只有父類有this$0成員變量,且指向了Person類的對象per。
總結:
成員內部類的非靜態子類可以是與其位於同一個外部類的子類,也可以是位於不同外部類的子類,還可以是一般類。
后兩種情況,必須在子類的構造方法中顯式添加 父類的外部類的對象.super(參數); 這樣一條語句,以保證為父類傳入其外部類的對象引用,繼而保證能調用父類的構造方法。