一、類初始化
1、一個類要創建實例需要先加載並初始化該類
(1)main方法所在的類需要先加載和初始化
上述的例子Father類和Son類之間沒有繼承關系,但是Son類當中有main方法,因此根據上述規則“main方法所在的類需要先加載和初始化”,可得結果和輸出結果相符,都是輸出(1),且這時候只有類初始化過程。
2、一個子類要初始化需要先初始化父類
這個例子和上一個例子相似,唯一的不同是Son類繼承了Father類,根據規則2,可以發現父類的靜態變量先行初始化,所以輸出結果是(2)然后再輸出(1)。
3、一個類初始化就是執行<clinit>()方法
(1)<clinit>()方法由靜態類變量顯示賦值代碼和靜態代碼塊組成
(2)類變量顯示賦值代碼和靜態代碼塊代碼從上到下順序執行
(3)<clinit>()方法只執行一次
根據規則3,我們可以設置下列對造組,由下列試驗得出的結果也佐證了規則3。
public class Son{ private static int j = method2(); private static int i = method1(); private static int method2() { System.out.println("(2)"); return 0; } private static int method1() { System.out.println("(1)"); return 0; } public static void main(String[] args) { } } 輸出結果: (2) (1) public class Son{ private static int i = method1(); //調換i和j的聲明順序 private static int j = method2(); private static int method2() { System.out.println("(2)"); return 0; } private static int method1() { System.out.println("(1)"); return 0; } public static void main(String[] args) { } } 輸出結果: (1) (2)
二、實例初始化
1、實例初始化就是執行<init>()方法
(1)<init>()方法可能重載有多個,有幾個構造器就有幾個<init>方法
(2)<init>()方法由非靜態實例變量顯示賦值代碼和非靜態代碼塊、對應構造器代碼組成
(3)非靜態實例變量顯示賦值代碼和非靜態代碼塊代碼從上到下順序執行,而對應構造器的代碼最后執行
根據上述規則,還可以再設立對照組,可以發現非靜態實例變量和非靜態代碼塊的初始化順序是按從上到下的順序執行的。
(4)每次創建實例對象,調用對應構造器,執行的就是對應的<init>方法
(5)<init>方法的首行是super()或super(實參列表),即對應父類的<init>方法
根據上述第5點,可以發現父類的構造方法都是先於子類的構造方法執行,在初始化子類實例的時候,因為其實子類的構造方法當中固定有一個super()方法,用於執行父類的構造方法。
class Father{ Father(){ System.out.println("Father的無參構造方法"); } } public class Son extends Father{ Son(){ System.out.println("Son的無參構造方法"); } public static void main(String[] args) { Son son = new Son(); } } 輸出結果: Father的無參構造方法 Son的無參構造方法
三、方法重寫對實例初始化的影響
(1)父類實例變量初始化當中用到的是子類重寫的方法