類中靜態代碼、非靜態代碼、建構函式等在初始化時它們的順序是不一樣的。
1. 靜態代碼的初始化
靜態程式碼封裝括static field和static block
例1:如下代碼:
class Bowl { Bowl(int marker) { //(1-1-1) (1-2-1)(3-1-1)(3-2-1)(3-3-1) System.out.println("Bowl(" + marker + ")"); } void f1(int marker) { //(1-3-1)(3-4-1) System.out.println("f1(" + marker + ")"); }}class Table { static Bowl bowl1 = new Bowl(1); //(1-1) Table() { //(1-3) System.out.println("Table()"); bowl2.f1(1); } void f2(int marker) { System.out.println("f2(" + marker + ")"); } static Bowl bowl2 = new Bowl(2); //(1-2)}class Cupboard { Bowl bowl3 = new Bowl(3); //(3-3) static Bowl bowl4 = new Bowl(4); //(3-1) Cupboard() { //(3-4) System.out.println("Cupboard()"); bowl4.f1(2); } void f3(int marker) { System.out.println("f3(" + marker + ")"); } static Bowl bowl5 = new Bowl(5); //(3-2)}public class StaticInitialization { public static void main(String[] args) { System.out.println("Creating new Cupboard() in main"); //(4) new Cupboard(); //(5) System.out.println("Creating new Cupboard() in main"); //(6) new Cupboard(); //(7) table.f2(1); //(8) cupboard.f3(1); //(9) } static Table table = new Table(); //(1) static { //(2) System.out.println("between table and cupboart"); } static Cupboard cupboard = new Cupboard(); //(3)}
靜態代碼的初始化以及非靜態執行個體的初始化在這個例子中都包括了。
結果如下:
2. 帶繼承的初始化
例2,如下代碼:
class Insect { private int i = 9; protected int j; Insect() { System.out.println("i = " + i + ", j = " + j); j = 39; } private static int x1 = printInit("static Insect.x1 initialized"); static int printInit(String s) { System.out.println(s); return 47; }}public class Beetle extends Insect { private int k = printInit("Beetle.k initialized"); public Beetle() { System.out.println("k = " + k); System.out.println("j = " + j); } private static int x2 = printInit("static Beetle.x2 initialized"); public static void main(String[] args) { System.out.println("Beetle constructor"); Beetle b = new Beetle(); }}
輸出:
3. 初始化順序總結
初始化按照下面的順序執行:
(1) 靜態代碼的初始化:包括static field 和 static block。靜態代碼的初始化在當載入類的時候執行,即首次用到類的時候,如首次訪問類的靜態成員、靜態函數,建立該類的對象。
注意:靜態代碼的初始化在載入類時執行且僅執行一次。
(2) 執行個體代碼初始化:包括執行個體變數和執行個體代碼塊。建立對象時進行執行個體變數的初始化。更確切的說是在建構函式顯式或隱式的調用父建構函式之後(即父建構函式執行完成之後,是個遞迴的過程)完成初始化。例2充分說明了這一點。
(3) 建構函式執行:在完成執行個體代碼初始化後,本類的建構函式開始執行,此時建構函式中顯式或隱式的調用父建構函式已經執行完畢,在(2)執行個體代碼的初始化之前就已經完成。
4. 原始類型和物件類型的預設初始化值
(1) 執行個體變數和靜態變數
(2) 局部變數
局部變數沒有預設值,在使用直線必須初始化,否則出現編譯器錯誤。
(3) 已指派空間的數組的預設值
對於已指派空間的數組中的每個值來說,無論此數組是執行個體數組還是局部數組都會有預設值,根據類型的不同,預設值與(1)中表格中的一樣。
如下代碼:
public class ArrayInit { public void test() { int c = 1; int b; //compiler error, it must be initialized before used int[] a = new int[2]; // primitice types, default values are 0 String[] s = new String[2];// reference types, default values are null System.out.println(c + " " + b + " " + a[0] + " " + s[0]); } public static void main(String[] args) { new ArrayInit().test(); }}
編譯結果: