偶爾翻到了關於Java對象初始化順序的面試題,重新復習了一下,順便做筆記。
1.父類子類構造函數執行的先后順序
public class Test2 { public int Field; //step 1 public Test2(){ Field = 1; } } /*************************************************/ /** * 次類的目的僅是為了驗證父類子類構造函數執行的先后順序 */ public class Test3 extends Test2{ //step 2 public Test3(){ Field = 2; } public static void main(String[] args) { Test3 t3 = new Test3(); System.out.println("對象t3中字段的值是【" + t3.Field + "】"); /************************************\ * 輸出結果 * 對象t3中字段的值是【2】 \************************************/ } }
結論:實例化一個對象,構造的執行順序是由父類到子類的順序,即Test2->Test3
2.構造函數初始化和內聯方式初始化
/**
* 此類目的僅是為了驗證以內聯的方式初始化字段和構造函數中初始化的
* 字段的先后順序
*
* 內聯初始化的內聯的意思,就是在聲明字段的時候同時進行初始化賦值。
*/
public class Test1 {
public int Field = 1;//step 1
/**
* step 2
*/
public Test1() { Field = 2; } public static void main(String[] args) { Test1 t1 = new Test1(); System.out.println("對象t1中字段的值是【" + t1.Field + "】"); /************************************\ * 輸出結果 * 對象t1中字段的值是【2】 \************************************/ } }
結論:實例化一個對象會先執行以內聯方式初始化字段的代碼,然后再去執行構造函數內的內容
3.初始化塊和初始化塊(靜態)
public class Test5 { public static int Field; //初始化塊(靜態) static { Field = 1; } //初始化塊 { Field = 2; } public static void main(String[] args) { System.out.println("字段Field的值是【" + Field + "】"); /*************************************\ * 輸出結果 * 字段Field的值是【1】 \*************************************/ } }
結論:初始化塊要優先於靜態初始化塊執行(錯誤結論)
總感覺這個結論怪怪的,然后查了一些資料,得知初始化塊只有在實例化一個對象的時候才會執行
public class Test5 { public static int Field; //初始化塊(靜態) static { Field = 1; } //初始化塊 { Field = 2; } public static void main(String[] args) { System.out.println("對象未被實例化之前,Field的值是【" + Field + "】"); Test5 test5 = new Test5(); System.out.println("對象被被實例化之后,Field的值是【" + Field + "】"); //為了驗證每次實例化對象都會調用初始化器 Field = 3; System.out.println("給字段Field賦值,Field的值是【" + Field + "】"); Test5 test5_0 = new Test5(); System.out.println("再次實例化對象之后,Field的值是【" + Field + "】"); /*************************************\ *對象未被實例化之前,Field的值是【1】 *對象被被實例化之后,Field的值是【2】 *給字段Field賦值,Field的值是【3】 *再次實例化對象之后,Field的值是【2】 \*************************************/ } }
為了驗證上邊提到的紅色字體部分正確性,還特意的將Field的值賦值為3並再次實例化 對象
結論:初始化器只有當被實例化的時候才會執行,並且每次實例化都會執行,靜態初始化器有先於初始化器執行
4.面試題一
public class Test6 { public static int i = Test7.j; { i++; } static { i = 0; } public Test6() { i++; } } /*********************************************/ public class Test7 extends Test6 { public static int j = Test6.i; static { j++; } { j++; } } /********************************************/ public class Main { public static void main(String[] args) { Test7 t7 = new Test7(); System.out.println("字段I的值是【" + Test6.i + "】"); System.out.println("字段J的值是【" + Test7.j + "】"); } }
5.面試題二
public class Test6 { public static int i = Test7.j; { i++; } static { i = 0; } public Test6() { i++; } } /*********************************************/ public class Test7 { public static int j = Test6.i; static { j++; } { j++; } } /*********************************************/ public class Main { public static void main(String[] args) { Test7 t7 = new Test7(); System.out.println("字段I的值是【" + Test6.i + "】"); System.out.println("字段J的值是【" + Test7.j + "】"); } }