2012-12-19 27 views
23

我有2類:靜態初始化器在構造函數之後運行,爲什麼?

類A:B

public class A { 
    static B b = new B(); 

    static { 
     System.out.println("A static block"); 
    } 

    public A() { 
     System.out.println("A constructor"); 
    } 
} 

類別:

public class B { 
    static { 
     System.out.println("B static block"); 
     new A(); 
    } 

    public B() { 
     System.out.println("B constructor"); 
    } 
} 

創建剛剛創建新A中的主要類:

public class Main { 
    public static void main(String[] args) { 
     new A(); 
    } 
} 

的我得到的輸出是:

B static block 
A constructor 
B constructor 
A static block 
A constructor 

如您所見,A的構造函數在其靜態初始化器之前被調用。

我知道它與我創建的循環依賴關係有關,但我的印象是靜態初始化應始終在構造函數之前運行。

發生這種情況的原因是什麼(技術上在java實現中)?

建議避免使用靜態初始化器嗎?

+0

誰低估了請留下評論 –

+2

好問題其實+1 .. :) – PermGenError

+0

@AviramSegal有些人習慣性地低估了..他們從來沒有讀過整個問題,通過閱讀標題,他們低估了這個問題。 – Ravi

回答

23
static B b = new B(); 

是前

static { 
    System.out.println("A static block"); 
} 

所以,你需要打印"A static block"之前在B實例進行初始化。

初始化B類意味着您需要創建一個A實例。所以在構造A實例之前,無法打印「靜態塊」。

是的,A的靜態初始化爲啓動在構造函數啓動之前,但除了死鎖之外,沒有其他解決方案需要您使用的序列。

注意預警the specification

因爲Java編程語言是多線程的,一類或接口的初始化階段 需要仔細同步,因爲一些 其他線程試圖初始化同一類或接口 在同一時間。 也有可能初始化 類或接口可能被遞歸請求作爲 該類或接口初始化的一部分;例如,類A中的變量 初始值設定項可能會調用不相關類B的方法 ,該方法可能會調用A類的方法。 Java虛擬機的實現負責使用以下 程序照顧 同步和遞歸初始化[商務部繼續與完整的程序]

最佳做法,在Java中其他語言,基本上是爲了避免循環依賴,因爲他們的解析可能很難預測。

+1

我會理解一個錯誤,但爲什麼允許這種不一致的行爲?還有,找不到那個 –

+0

好的文檔,我錯過了說明書,謝謝! –

相關問題