1. 程式人生 > >Java類初始化順序

Java類初始化順序

我們大家都知道,對於靜態變數、靜態初始化塊、變數、初始化塊、構造器,它們的初始化順序以此是(靜態變數、靜態初始化塊)>(變數、初始化塊)>構造器。我們也可以通過下面的測試程式碼來驗證這一點: 
public class InitialOrderTest {

	// 靜態變數
	public static String staticField = "靜態變數";
	// 變數
	public String field = "變數";

	// 靜態初始化塊
	static {
		System.out.println(staticField);
		System.out.println("靜態初始化塊");
	}

	// 初始化塊
	{
		System.out.println(field);
		System.out.println("初始化塊");
	}

	// 構造器
	public InitialOrderTest() {
		System.out.println("構造器");
	}

	public static void main(String[] args) {
		new InitialOrderTest();
	}
}
執行以上程式碼,我們會得到如下的輸出結果: 
靜態變數
靜態初始化塊
變數
初始化塊
構造器

單個類的初始化順序:

a. 靜態變數/域

b. 普通成員/域

c. 建構函式

那麼對於繼承情況下又會怎樣呢?我們仍然以一段測試程式碼來獲取最終結果: 
Java程式碼 
class Parent {
	// 靜態變數
	public static String p_StaticField = "父類--靜態變數";
	// 變數
	public String p_Field = "父類--變數";

	// 靜態初始化塊
	static {
		System.out.println(p_StaticField);
		System.out.println("父類--靜態初始化塊");
	}

	// 初始化塊
	{
		System.out.println(p_Field);
		System.out.println("父類--初始化塊");
	}

	// 構造器
	public Parent() {
		System.out.println("父類--構造器");
	}
}

public class SubClass extends Parent {
	// 靜態變數
	public static String s_StaticField = "子類--靜態變數";
	// 變數
	public String s_Field = "子類--變數";
	// 靜態初始化塊
	static {
		System.out.println(s_StaticField);
		System.out.println("子類--靜態初始化塊");
	}
	// 初始化塊
	{
		System.out.println(s_Field);
		System.out.println("子類--初始化塊");
	}

	// 構造器
	public SubClass() {
		System.out.println("子類--構造器");
	}

	// 程式入口
	public static void main(String[] args) {
		new SubClass();
	}
}
執行一下上面的程式碼,結果馬上呈現在我們的眼前: 
父類--靜態變數
父類--靜態初始化塊
子類--靜態變數
子類--靜態初始化塊
父類--變數
父類--初始化塊
父類--構造器
子類--變數
子類--初始化塊
子類--構造器

繼承體系中的初始化順序:

a. 繼承體系中所有靜態成員/域(先父類,後子類)

b. 父類普通成員/域

c. 父類建構函式

d. 子類普通成員/域

e. 子類建構函式


現在,結果已經不言自明瞭。大家可能會注意到一點,那就是,並不是父類完全初始化完畢後才進行子類的初始化,實際上子類的靜態變數和靜態初始化塊的初始化是在父類的變數、初始化塊和構造器初始化之前就完成了。 

那麼對於靜態變數和靜態初始化塊之間、變數和初始化塊之間的先後順序又是怎樣呢?是否靜態變數總是先於靜態初始化塊,變數總是先於初始化塊就被初始化了呢?實際上這取決於它們在類中出現的先後順序。我們以靜態變數和靜態初始化塊為例來進行說明。 

同樣,我們還是寫一個類來進行測試: 
public class TestOrder {
	// 靜態變數
	public static TestA a = new TestA();

	// 靜態初始化塊
	static {
		System.out.println("靜態初始化塊");
	}

	// 靜態變數
	public static TestB b = new TestB();

	public static void main(String[] args) {
		new TestOrder();
	}
}

class TestA {
	public TestA() {
		System.out.println("Test--A");
	}
}

class TestB {
	public TestB() {
		System.out.println("Test--B");
	}
}

執行上面的程式碼,會得到如下的結果: 
Test--A
靜態初始化塊
Test--B

大家可以隨意改變變數a、變數b以及靜態初始化塊的前後位置,就會發現輸出結果隨著它們在類中出現的前後順序而改變,這就說明靜態變數和靜態初始化塊是依照他們在類中的定義順序進行初始化的。同樣,變數和初始化塊也遵循這個規律。 

瞭解了繼承情況下類的初始化順序之後,如何判斷最終輸出結果就迎刃而解了。