先說結論
對於具有繼承關係的類,它們的類和對象構造順序爲:父類的類構造器() -> 子類的類構造器() -> 父類成員變量的賦值和實例代碼塊 -> 父類的構造函數 -> 子類成員變量的賦值和實例代碼塊 -> 子類的構造函數。
實驗代碼如下:
public class ExtensionTest {
public static void main(String[] args) {
new SubClass();
}
}
class SuperClass
{
{
System.out.println("我是父類實例塊");
}
static {
System.out.println("我是父類類構造塊");
}
public SuperClass()
{
System.out.println("我是父類構造函數塊");
}
}
class SubClass extends SuperClass
{
{
System.out.println("我是子類實例塊");
}
static {
System.out.println("我是子類類構造塊");
}
public SubClass()
{
System.out.println("我是子類構造函數塊");
}
}
結果:
我是父類類構造塊
我是子類類構造塊
我是父類實例塊
我是父類構造函數塊
我是子類實例塊
我是子類構造函數塊
解釋:
類構造塊是初始化類的時候執行的,而初始化類首先得加載類(不加載類進內存當然沒法初始化)。
類實例塊是放在該類構造函數最前面和父類構造函數之後執行的。因爲子類的構造函數調用之前,會先調用父類的構造函數。
基於上述兩條規則,我們再來看執行順序。
new SubClass()也就是要構造SubClass這個類的一個對象,而要構造這個對象,首先必須把這個類的描述、定義加載進內存(類加載)。因此要先加載這個類(不過此時還未初始化)。
加載完這個類之後,想要構造這個類的對象。但是此時這個類的靜態變量還未被初始化,因此要先初始化這個類,但是初始化這個類需要先初始化它的父類,因此此時就變成了,加載父類->初始化父類(調用靜態塊,即類構造塊)
->初始化子類(調用靜態塊,即類構造塊)。
然後就可以構造這個類的對象了,構造這個類的對象之前,要先構造父類對象,因此會先調用父類的構造函數,而調用父類構造函數之前又會先調用父類的實例塊。
然後就到了子類構造函數,然而執行之前一樣要先調用子類的實例塊,最後纔是子類的構造函數的函數體。