1. 程式人生 > >Think In Java讀書筆記:內部類覆蓋及其初始化

Think In Java讀書筆記:內部類覆蓋及其初始化

圖片 10.10 clas 構造 col 向上轉型 pan center 類初始化

  本文相關章節:第十章 內部類 10.10 內部類可以被覆蓋嗎

  在讀至本節第二個範例代碼時(及下方的代碼),我對輸出結果中的第一個“Egg.Yolk()”很不理解,為什麽它會第一個地方輸出。

  我起初認為是在調用BigEgg.Yolk的構造器時初始化其父類調用父類構造器輸出的,畢竟在main方法中第一行是在調用BigEgg的構造器,而它的構造器中首先調用了BigEgg.Yolk的構造器,在調用BigEgg.Yolk構造器時初始化其父類Egg.Yolk才輸出的“Egg.Yolk()”。但書中卻明確說明了第二個“EGG.Yolk()”是子類BigEgg.Yolk初始化其父類輸出的,這就使我產生了迷惑——那第一個“Egg.Yolk()”到底是怎麽輸出的呢?

  (書中範例代碼,原文中因為是第二個範例所有的類都命名為“xxx2”,在這裏我將所有的2都刪去了)

/**
 * Created by dsa44 on 2018/4/21.
 */
class Egg{

    class Yolk{
        public Yolk(){
            System.out.println("Egg.Yolk()");
        }
        public void f(){
            System.out.println("Egg.Yolk.f()");
        }
    }

    private Yolk y = new
Yolk(); public Egg(){ System.out.println("new Egg()"); } public void insertYolk(Yolk yy){ y = yy; } public void g(){ y.f(); } } public class BigEgg extends Egg{ public class Yolk extends Egg.Yolk{ public Yolk() { System.out.println(
"BigEgg.Yolk()"); } public void f(){ System.out.println("BigEgg.Yolk.f()"); } } public BigEgg(){ insertYolk(new Yolk()); } public static void main(String[] args){ Egg e = new BigEgg(); e.g(); } }/* 輸出結果 Egg.Yolk() new Egg() Egg.Yolk() BigEgg.Yolk() BigEgg.Yolk.f() */

  這其中的關鍵點也是書中沒提到的我認為就是BigEgg構造器到底是在何時開始運行的(實際上也只有BigEgg的構造器沒有輸出任何信息),於是我在BigEgg的構造器中添加了輸出“new BigEgg()”的語句。結果如下:

  技術分享圖片

  我想在這裏就已經真相大白了:

  在調用BigEgg構造器時,其構造器首先調用了其父類Egg的構造器(即首先初始化它自己的父類),在初始化父類Egg時首先初始化了父類的數據域,而它的父類Egg的數據域只有一個私有的Egg.Yolk類型的引用y,且在這裏對y進行了初始化,調用它的構造器Egg.Yolk(),故輸出了第一句“Egg.Yolk()”。

  在初始化Egg的數據域後便運行了Egg的構造器(輸出“new Egg()”),在自己的父類完成初始化後BigEgg的構造器開始運行(輸出“new BigEgg()”),然後運行父類Egg的方法insertYolk,在其參數部分運行BigEgg.Yolk的構造器,在這裏就變成了我剛開始提到的那一部分,於是相繼輸出了“Egg.Yolk()”“BigEgg.Yolk()”,最後雖然BigEgg.Yolk向上轉型,但因為動態綁定的關系,在調用e.f()時,依舊輸出的時屬於BigEgg.Yolk的f方法,輸出“BigEgg.Yolk.f()”。

  總結:在這裏遇到問題的主要原因還是因為對於第五章初始化部分了解的不夠詳細(知識點:父類初始化是在子類構造器未運行前就進行的,也可以說是在調用子類構造器時就開始了父類的初始化並在其初始化完成後開始運行子類的構造器)。

Think In Java讀書筆記:內部類覆蓋及其初始化