一道面試題引起的思考

public class Parent {
    public static String p_str1 = "1";
    public String p_str2 = "2";

    static {
        System.out.println(p_str1);
        System.out.println("3");
    }

    {
        System.out.println(p_str2);
        System.out.println("4");
    }

    public Parent() {
        System.out.println("5");
    }

}

class Son extends Parent {
    public static String s_str1 = "6";
    public String s_str2 = "7";

    static {
        System.out.println(s_str1);
        System.out.println("8");
    }

    {
        System.out.println(s_str2);
        System.out.println("9");
    }

    public Son() {
        System.out.println("10");
    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("11");
        Son s = new Son();
    }

}

打印的結果十多?先留點懸念,咱們複習一下類的加載觸發條件及執行順序;參看:http://blog.csdn.net/thm521888/article/details/18424351java

知識點一:類加載觸發條件
(1)、調用靜態成員時,會加載靜態成員真正所在的類及其父類。 經過子類調用父類的靜態成員時,只會加載父類而不會加載子類。 (這裏須要補充的是,靜態方法也適用這條規則)
(2)、第一次 new 對象的時候 加載(第二次再 new 同一個類時,不需再加載)。 
(3)、加載子類會先加載父類。(覆蓋父類方法時所拋出的異常不能超過父類定義的範圍) 
函數

知識點二:類加載的順序: 
1.加載靜態成員/代碼塊: 
先遞歸地加載父類的靜態成員/代碼塊(Object的最早);再依次加載到本類的靜態成員。 
同一個類裏的靜態成員/代碼塊,按寫代碼的順序加載。 
若是其間調用靜態方法,則調用時會先運行靜態方法,再繼續加載。同一個類裏調用靜態方法時,能夠不理會寫代碼的順序。 
調用父類的靜態成員,能夠像調用本身的同樣;但調用其子類的靜態成員,必須使用「子類名.成員名」來調用。 
2.加載非靜態成員/代碼塊:(實例塊在建立對象時纔會被加載。而靜態成員在不建立對象時能夠加載) 
先遞歸地加載父類的非靜態成員/代碼塊(Object的最早);再依次加載到本類的非靜態成員。 
同一個類裏的非靜態成員/代碼塊,按寫代碼的順序加載。同一個類裏調用方法時,能夠不理會寫代碼的順序。 
但調用屬性時,必須注意加載順序。通常編譯不經過,若是能在加載前調用,值爲默認初始值(如:null 或者 0)。 
調用父類的非靜態成員(private 除外),也能夠像調用本身的同樣。 
3.調用構造方法:
先遞歸地調用父類的構造方法(Object的最早)也就是上溯下行;
默認調用父類空參的,也可在第一行寫明調用父類某個帶參的。spa

知識點三:建立對象時類的加載
靜態成員/代碼塊:用於給類初始化,類加載時就會被加載執行,只加載一次。
非靜態成員/代碼塊:用於給對象初始化的。只要創建對象該部分就會被執行,且優先於構造函數。
構造方法:  給對應對象初始化的,創建對象時,選擇相應的構造函數初始化對象。
 建立對象時,三者被加載執行順序:靜態成員/代碼塊--->非靜態成員/代碼塊--->構造方法.net


瞭解了以上知識,咱們進一步分析習題。code

1.程序的入口main方法,該方法爲靜態的方法,則java虛擬機須要加載該方法的所在的類及父類。對象

2.類的加載順序告訴咱們先祖先類再子類,因此先加載Parent.class,因爲Parent.class中有靜態的代碼塊/方法,執行之;打印結果:1  3blog

3.Parent.class加載完畢,則開始加載子類Son.class ,同上有靜態代碼塊/方法  ,執行之;打印結果:6 8遞歸

4.Son.class加載完畢,如今輪到咱們main方法出場了,剛纔進入main方法半天,什麼都沒撈着,怎一個慘字了得;正所謂:咫尺天涯get

終於輪到出場了
虛擬機

 System.out.println("11");

執行之;打印結果: 11

5.接下來Son s = new Son(); 開始發威了,第一次 new 對象的時候(非new也能夠)加載,第二次再 new 同一個類時,不需再次加載。

實際上Parent.class和Son.class已經加載好了,不須要再次加載;接着建立對象,三者被加載執行順序:靜態代碼塊--->構造代碼塊--->構造函數(知識點三)

6.按照知識點三:先父類後子類執行建立對象的類。父類的對象,2 4 5

7.子類對象,7 9 10


作實驗的過程當中,咱們能夠如今將子類實例化給屏蔽掉,分析完1-4步驟,再來分析後面的部分。 // Son s = new Son();


以上分析,僅供參考,有不對的地方還請您指出;提出您的寶貴意見

執行結果:

javac Parent.java

java Son1368112457910

相關文章
相關標籤/搜索