下面是在網上找到的比較典型的例子,以此來說明
例一:
class A { static { System.out.println("A的靜態塊"); } private static String staticStr = getStaticStr(); private String str = getStr(); { System.out.println("A的實例塊"); } public A() { System.out.println("A的構造方法"); } private static String getStaticStr() { System.out.println("A的靜態屬性初始化"); return null; } private String getStr() { System.out.println("A的實例屬性初始化"); return null; } public static void main(String[] args) { new B(); new B(); } } class B extends A{ private static String staticStr = getStaticStr(); static { System.out.println("B的靜態塊"); } { System.out.println("B的實例塊"); } public B() { System.out.println("B的構造方法"); }
private String str = getStr(); private static String getStaticStr() { System.out.println("B的靜態屬性初始化"); return null; } private String getStr() { System.out.println("B的實例屬性初始化"); return null; } }
該段代碼的執行結果為:
A的靜態塊
A的靜態屬性初始化
B的靜態屬性初始化
B的靜態塊
A的實例屬性初始化
A的實例塊
A的構造方法
B的實例塊
B的實例屬性初始化
B的構造方法
A的實例屬性初始化
A的實例塊
A的構造方法
B的實例塊
B的實例屬性初始化
B的構造方法
由此可見,實例化子類的時候,若此類未被加載過,首先加載是父類的類對象,然后加載子類的類對象,接着實例化父類,最后實例化子類,若此類被加載過,不再加載父類和子類的類對象。
接下來是加載順序,當加載類對象時,首先初始化靜態屬性,然后執行靜態塊;當實例化對象時,首先執行構造塊(直接寫在類中的代碼塊),然后執行構造方法。至於各靜態塊和靜態屬性初始化哪個些執行,是按代碼的先后順序。屬性、構造塊(也就是上面的實例塊)、構造方法之間的執行順序(但構造塊一定會在構造方法前執行),也是按代碼的先后順序。
例二:
public class EXA { private static EXA a = new EXA(); static { System.out.println("父類--靜態代碼塊"); } public EXA() { System.out.println("父類--構造函數"); } { System.out.println("父類--非靜態代碼塊"); } public static void main(String[] args) { new EXC(); new EXC(); } } class EXC extends EXA { private static EXC b = new EXC(); static { System.out.println("子類--靜態代碼塊"); } { System.out.println("子類--非靜態代碼塊"); } public EXC() { System.out.println("子類--構造函數"); } }
該段代碼的執行結果為:
父類--非靜態代碼塊
父類--構造函數
父類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
子類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
分析(非靜態代碼塊即構造塊):
首先要加載父類EXA,由於A的靜態屬性在靜態塊的前面,先初始化靜態屬性(new EXA())(父類--非靜態代碼塊;父類--構造函數),然后是靜態塊(父類--靜態代碼塊);
加載子類EXC,由於EXC的靜態屬性也在靜態塊的前面,先初始化靜態屬性(new EXC()),實例化子類對象的時候會先實例化父類,所以執行的順序為(父類--非靜態代碼塊;父類--構造函數;子類--非靜態代碼塊;子類--構造函數),然后是靜態塊(子類--靜態代碼塊)
實例化父類EXA對象:父類--非靜態代碼塊;父類--構造函數;
實例化子類EXC對象:子類--非靜態代碼塊;子類--構造函數;
第二個new EXC():因為父類和子類都已加載,只需依次實例化父類對象和子類對象(父類--非靜態代碼塊;父類--構造函數;子類--非靜態代碼塊;子類--構造函數;)
推測:若將EXA的靜態塊和靜態屬性的初始化換位置,執行結果應該為:
父類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
子類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
public class EXA { static { System.out.println("父類--靜態代碼塊"); } private static EXA a = new EXA(); public EXA() { System.out.println("父類--構造函數"); } { System.out.println("父類--非靜態代碼塊"); } public static void main(String[] args) { new EXC(); new EXC(); } } class EXC extends EXA { private static EXC b = new EXC(); static { System.out.println("子類--靜態代碼塊"); } { System.out.println("子類--非靜態代碼塊"); } public EXC() { System.out.println("子類--構造函數"); } }
運行發現,結果證實這樣。