2017-03-22 67 views
3

在下面的代碼段爲什麼getX()方法執行第一而非構造:在執行構造的主體之前爲什麼的getX()方法執行第一而不是構造

public class ConsructorQuestion { 

    int x = getX(); // same this.getX(); 
    public int getX() { 
     System.out.println(x + " via method "); 
     return 10; 
    } 

    public ConsructorQuestion() { 
     System.out.println(x+" via constructor"); 
    } 

    public static void main(String[] args) { 
     ConsructorQuestion t = new ConsructorQuestion(); 
    } 

} 
+1

因爲這就是類初始化的工作原理。你爲什麼期望別的嗎? – shmosel

+1

它實際上是在這裏工作的實例初始化。 –

+0

[實例初始值設定項與構造函數有什麼不同?](https://stackoverflow.com/questions/1355810/how-is-an-instance-initializer-different-from-a-constructor)可能重複?還https://stackoverflow.com/questions/335311/static-initializer-in-java,https://stackoverflow.com/questions/12550135/static-block-vs-initializer-block-in-java,https:/ /stackoverflow.com/questions/6763550/why-java-instance-initializers以及與之相關的問題。 –

回答

6

實例變量被初始化(但在超類構造函數的主體被執行後)。

因此,在你的例子中,int x = getX();是在構造函數體之前執行的。

這相當於x初始化移動到構造函數的第一行:

int x; 
public int getX(){ 
    System.out.println(x+" via method "); 
    return 10; 
} 

public ConsructorQuestion() { 
    x = getX(); 
    System.out.println(x+" via constructor"); 
} 
5

字段初始化(和實例的初始化塊)由編譯器注入到每一個構造的開頭在類(緊接在super(...)的調用之後,隱式或顯式),如果構造函數沒有鏈接到同一類中的另一個(通過調用this(...))。所以,如果你看一下生成字節碼,你會看到你的類如下所示:

public class ConsructorQuestion { 

    int x;            // *** 
    public int getX(){ 
     System.out.println(x+" via method "); 
     return 10; 
    } 

    public ConsructorQuestion() { 
     this.x = getX();        // *** 
     System.out.println(x+" via constructor"); 
    } 

    public static void main(String[] args) { 
     ConsructorQuestion t = new ConsructorQuestion(); 
    } 

} 

構建實例時被JLS§12.5覆蓋在事情完成順序:

就在到新創建的對象的引用被作爲結果返回時,所指示的構造被處理使用下面的過程來初始化新的對象:

  1. 分配變元用於構造函數的ts爲此構造函數調用的新創建的參數變量。

  2. 如果此構造函數以相同類中另一個構造函數的顯式構造函數調用(第8.8.7.1節)開頭(使用此參數),則計算參數並使用這五個相同的步驟來遞歸構造函數調用。如果構造函數的調用突然完成,則此過程由於同樣的原因突然完成;否則,請繼續執行步驟5.

  3. 此構造函數不是以相同類中另一個構造函數的顯式構造函數調用開始的(使用此方法)。如果此構造函數用於Object以外的類,則此構造函數將以顯式或隱式調用超類構造函數(使用super)開始。評估參數並使用這五個相同的步驟遞歸地處理該超類構造函數的調用。如果構造函數的調用突然完成,那麼出於同樣的原因,此過程會突然完成。否則,繼續步驟4

  4. 執行實例初始化和實例變量初始值設定爲這樣的類,實例指派變量初始化的值,以相應的實例變量,在它們出現的左到右的順序文本在類的源代碼中。如果執行這些初始化程序中的任何一個都會導致異常,則不會執行進一步的初始化程序,並且此過程會以相同的異常突然完成。否則,請繼續步驟5.

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

注#4和#5的順序。

+1

@AndyTurner:哦,兩個優點,固定。 –

0

Javac從類的開頭開始,首先初始化類成員,然後繼續使用main。

+1

但是,這裏的問題是實例初始化,而不是類初始化,這意味着'main'首先被調用。 –

+0

Java main()與C/C++ main有點不同。在C/C++中,除了全局變量,構造函數被稱爲post main()。但是,在java中,類成員是按照從上到下的順序初始化的,然後是主對象構造函數。 – vivekn

相關問題