1. 程式人生 > >java 用自身類的物件初始化靜態變數 執行順序

java 用自身類的物件初始化靜態變數 執行順序

    在上一篇文章中, 探索了在一條繼承鏈中靜態初始化塊和靜態變數初始化、初始化塊和例項域初始化、建構函式的執行順序(見http://blog.csdn.net/maple1997/article/details/79508981),現在繼續探索一下如果new一個自身類的物件賦值給靜態變數來初始化的執行順序會是怎麼樣。
    以下是程式碼:
package initialization;
//new自身類物件來初始化靜態變數, 觀察構造順序
public class StaticVarNewItselfTest {
	static
	{
		System.out.println("main方法所在的類被載入\n");
	}
	public static void main(String[] args) {
		System.out.println("main開始");
		AnotherClass c = new AnotherClass();
		System.out.println("開始構造一個物件");
		StaticVarNewItself t2 = new StaticVarNewItself();
		System.out.println("main結束");
	}
}

class StaticVarNewItself{
	public StaticVarNewItself(){
		System.out.println("new ()");
	}
//	new自身類物件來初始化靜態變數
	static
	{
		System.out.println("static blockB1");
	}
	
	public static StaticVarNewItself t1 = new StaticVarNewItself(); 
	
	{
		System.out.println("blockA");
	}
	
	static {
		System.out.println("static blockB2");
	}
}

class AnotherClass{
	static {
		System.out.println("AnotherClass載入");
	}
}
執行結果:
main方法所在的類被載入

main開始
AnotherClass載入
開始構造一個物件
static blockB1
blockA
new ()
static blockB2
blockA
new ()
main結束
結果分析:
    1.main()所在的類最先載入, 再執行main方法
    2.在main方法中, 一邊執行一邊載入所需要的類
    3.new自身類物件來初始化靜態變數的順序: 
        之前的static{}和靜態變數的初始化, 
        {}和例項域的初始化, 
        建構函式, 
        之後的static{}和之後的靜態變數的初始化
發現{}和例項域的初始化還有建構函式的執行的次序被提前了!(按照正常的順序應該是:靜態初始化塊和靜態變數初始化>初始化塊和例項域初始化>建構函式),那麼如果在例項域中使用還沒有被初始化的靜態變數的值會發生什麼呢?
package initialization;
//new自身類物件來初始化靜態變數, 觀察構造順序
public class StaticVarNewItselfTest {
	static
	{
		System.out.println("main方法所在的類被載入\n");
	}
	public static void main(String[] args) {
		System.out.println("main開始");
		AnotherClass c = new AnotherClass();
		System.out.println("開始構造一個物件");
		StaticVarNewItself t2 = new StaticVarNewItself();
		
		System.out.println("StaticVarNewItself.staticValue = " + StaticVarNewItself.staticValue);
		System.out.println("StaticVarNewItself.t1.value = " + StaticVarNewItself.t1.value);
		System.out.println("StaticVarNewItself.t2.value = " + t2.value);
		System.out.println("main結束");
	}
}

class StaticVarNewItself{
	public StaticVarNewItself(){
		System.out.println("new ()");
		value = staticValue;
		System.out.println("使用了靜態變數staticValue的值");
	}
//	new自身類物件來初始化靜態變數
	static
	{
		System.out.println("static blockB1");
	}
	
	public static StaticVarNewItself t1 = new StaticVarNewItself(); 
	
	{
		System.out.println("blockA");
	}
	
	static {
		System.out.println("static blockB2");
	}
	
	public static int staticValue;
	static {
		//經過一些複雜的計算
		staticValue = 250;
		System.out.println("靜態變數staticValue初始化完成");
	}
	
	int value;
}

class AnotherClass{
	static {
		System.out.println("AnotherClass載入");
	}
}
執行結果:
main方法所在的類被載入

main開始
AnotherClass載入
開始構造一個物件
static blockB1
blockA
new ()
使用了靜態變數staticValue的值
static blockB2
靜態變數staticValue初始化完成
blockA
new ()
使用了靜態變數staticValue的值
StaticVarNewItself.staticValue = 250
StaticVarNewItself.t1.value = 0
StaticVarNewItself.t2.value = 250
main結束
所有的一切都安安靜靜地發生,MyEclipse編譯器不會警告,執行時也沒有拋異常,只是並沒有像預期那樣取得靜態變數staticValue的值,而是取到了預設值0。這說明了如果一個類的靜態變數的初始化需要new一個自身類的物件, 則一定要注意其他靜態變數的初始化和獲取該靜態變數的值的先後次序。