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