2012-12-12 99 views
2

我想問一下,爲什麼下面的代碼會導致錯誤:的Java初始化順序錯誤

class A 
{ 
    A() 
    { 
     statObj.x = 5; 
    } 

    int x; 
    static A statObj = new A(); 
} 

我得到的ExceptionInInitializerError。我不明白爲什麼。在這種情況下,靜態變量statObj將被初始化爲第一個。所以,如果我是對的,靜態對象statObj = new A()將被創建爲第一個。

這個內部靜態對象的創建和初始化的順序是什麼?在內部靜態對象構造函數調用statObj.A()之前,是不是將statObj.x默認值初始化爲0值?如果那樣,爲什麼statObj.x的行爲像它沒有被初始化(我爭取它是默認初始化0值)?

還有一個爲什麼這個問題只出現在構造函數中,而不是在方法中?下面的代碼工作正常:

 class A 
     { 
      A() 
      { 
      } 

      void met1() 
      { 
       statObj.x = 5; 
      } 

      int x; 
      static A statObj = new A(); 
     } 


     public MainClass 
     { 
      public static void main(String[] arg) 
      { 
       A a = new A(); 
       a.statObj.met1(); 
      } 
     } 
+3

你爲什麼認爲它會起作用? –

回答

0

你得到一個NullPointerException,因爲你正在嘗試已創建的對象之前,訪問存儲在靜態字段的實例。發生這種情況是因爲它只在構造函數完成後才創建。但是你從構造函數中調用它。

第二個代碼工作正常,因爲那裏的構造函數(它什麼都不做)有機會完成。

再次:

static A statObj = new A(); 

statObj將爲空,直到構造(new A())完成。

If create new object the order of creation is like this: - find A.class file, - initialization of static variables, - default initialzation of non static variables, - allocation memory for the object - explicit initialization of non static variables, - constructor execution

嗯,這裏的問題是,在「靜態變量初始化」你撥打的嘗試使用相同的靜態變量構造函數,如果你將在你未來的序列跳了一下。

So when we create statObj, shouldn't statObj.x be default initialize (by 0) before the statObj constructor is called ?

是的,但這不是問題在這裏。這裏的問題是statObj本身在其構造函數完成之前爲空。

statObj.x = 5;

如果你做了this.x,它會工作。但statObj當時仍然爲空。

+0

請檢查我寫給@NPE的評論回答 –

+0

現在我明白了。非常感謝您的幫助:) –

9

考慮發生了什麼。下面的靜態初始化:

static A statObj = new A(); 

調用A(),然後嘗試訪問statObj

A() { 
    statObj.x = 5; 
} 

然而,在這一點上statObj尚未初始化,因此null。 A NullPointerException被拋出,然後被翻譯成ExceptionInInitializerError(因爲在靜態初始化器中發生了NPE)。

第二個例子沒有這個問題,因爲當你試圖訪問statObj時,它已經完全初始化。

+2

不,「statObj」尚未分配,它將在構造函數「A()」完成後分配。 –

+0

@MarkRotteveel:公平點,我改進了措辭。 – NPE

+0

好吧,我理解你的解釋,但仍然不理解代碼行爲。如果創建新對象,創建順序如下: - 查找A.class文件, - 初始化靜態變量, - 非靜態變量的默認初始化**, - 對象的分配內存 - 顯式初始化非靜態變量, - 構造函數執行 所以當我們創建'statObj'時,不應該'statObj.x'在statObj構造函數被調用之前默認初始化(0)?如果不是這樣,爲什麼我們可以這樣做: 'class B { int y; B() { y = 5; } ' ? –

0

您正試圖在創建對象之前訪問對象(statObj.x)。試試這個:

class A 
{ 
    A() 
    { 
    } 

    int x; 
    static A statObj = new A(); 

    static { 
     statObj.x = 5; 
    } 
} 
0

問題是,你初始化一個靜態的構造函數包含這個靜態。

要正確完成construcor應具有該靜態值。但要有靜態的價值建設必須先完成。