2013-09-27 83 views
23

我試圖發現初始化發生的順序,或者說是爲什麼初始化按此順序發生的原因。由於代碼:Java靜態初始化命令

public class Main { 

    { 
     System.out.printf("NON-STATIC BLOCK\n"); 
    } 

    static{ 
     System.out.printf("STATIC BLOCK\n"); 
    } 

    public static Main m = new Main(); 

    public Main(){ 
     System.out.printf("MAIN CONSTRUCTOR\n"); 
    } 

    public static void main(String... args) { 
     //Main m = new Main(); 
     System.out.printf("MAIN METHOD\n"); 

    } 
} 

輸出:

STATIC BLOCK 

NON-STATIC BLOCK 

MAIN CONSTRUCTOR 

MAIN METHOD 

然而,在移動m的聲明之前初始化塊生產:

NON-STATIC BLOCK 

MAIN CONSTRUCTOR 

STATIC BLOCK 

MAIN METHOD 

,爲什麼它發生在我完全不知道這個命令。此外,如果我在m的聲明中刪除了static關鍵字,則init塊和構造函數都不會觸發。任何人都可以幫我解決這個問題嗎?

+1

請記住,「非靜態塊」中的代碼將被複制到每個構造函數中。只有初始化塊的相對順序很重要,只有在調用構造函數時(看似「之前」)纔會調用它們。 (在靜態初始化程序之前或之後,取決於您將移動的行放在哪裏)。 – millimoose

+0

現在真正奇怪的是,這意味着您可以在類自身完成初始化之前初始化一個類的實例這聽起來像是一個等待發生的奇怪的錯誤。 – millimoose

+0

@millimoose:謝謝 - 我在回答中添加了一些關於實例初始值設定項的內容。 –

回答

27

我認爲你只是缺少section 12.4.2 of the JLS,其中包括:

接下來,既可以執行類變量初始化和類的靜態初始化,或接口的字段初始化,在文本順序,如雖然他們是一個塊。

「在文字順序」部分是重要的一點。

如果從靜態的變量,實例變量改變m,則字段將不會被類初始化初始化 - 它只會通過例如初始化被初始化(即當一個實例構造) 。目前,這會導致堆棧溢出 - 創建一個實例都需要創建另一個實例,它需要創建另一個實例等

編輯:同樣section 12.5指定實例初始化,包括以下步驟:

  • 執行此類的實例初始化程序和實例變量初始值設定項,將實例變量初始值設定項的值分配給相應的實例變量,按照從左到右的順序,它們以文本形式顯示在類的源代碼中。如果執行這些初始化程序中的任何一個都會導致異常,則不會執行進一步的初始化程序,並且此過程突然以相同的異常完成。否則,請繼續步驟5.

  • 執行此構造函數的其餘部分。如果該執行突然完成,則此過程因相同原因突然完成。否則,此過程正常完成。

所以這就是爲什麼你在「主構造函數」之前看「非靜態BLOCK」。

+0

@SotiriosDelimanolis:對;將明確說明。 –

+3

我愛堆棧溢出的提及:) – Cruncher