2013-02-25 138 views
5

有一個代碼作爲初級Java開發人員的任務給出。我在五年的使用Java和這段代碼完全混淆了我:Java:對象的初始化順序

public class Main { 

    String variable; 

    public static void main(String[] args) { 
     System.out.println("Hello World!"); 
     B b = new B(); 
    } 

    public Main(){ 
     printVariable(); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in Main Class"; 
    } 
} 

public class B extends Main { 

    String variable = null; 

    public B(){ 
     System.out.println("variable value = " + variable); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in B Class"; 
    } 
} 

輸出將是:

Hello World! 
variable value = null 

但是,如果我們改變String variable = null;String variable;我們將有:

Hello World! 
variable value = variable is initialized in B Class 

第二個輸出對我來說更加清晰。 所以,據我所知inizialisation的在Java中這樣的順序:

  • 我們去的類層次結構的根(用於Java它總是對象類),當我們來到這根父類:
    • 所有靜態數據字段初始化;
    • 執行所有靜態字段初始值設定項和靜態初始化塊;
    • 所有非靜態數據字段被初始化;
    • 執行所有非靜態字段初始化程序和非靜態初始化塊;
    • 默認的構造函數被執行;
  • 然後,我們不斷爲底層子類的程序。

也有帖子裏面描述了一個超類的背景下this關鍵字的行爲 - Calling base class overridden function from base class method

基於上面給出的規則,我認爲有順序是這樣的:

  1. 我們將創建B類的新實例;
  2. 我們到部分類Main;
  3. 用null初始化main.variable;
  4. 然後我們轉移到Main類的默認構造函數;
  5. 構造在Main類調​​用方法b.printVariable(); (爲什麼不調用它main.printvariable我們沒有在這裏this鍵字?)
  6. 領域b.variable變量是在B級初始化
  7. 現在我們再回到類B;
  8. 我們應該初始化場b.variable與空值,是嗎?;
  9. B類的默認構造函數執行

請,能有人給的這種繼承i​​nizialisation序列是如何工作的一個完整的,全面的解釋。以及爲什麼更改String variable = null;String variable;導致另一個輸出。

+1

printVariable(會發生什麼)是一個非常誤導的方法名字 - 應該更像setVariable( ) – Jimmt 2013-02-25 17:50:45

+1

你已經寫了5年的Java,你不知道如何使用調試器? (單步執行代碼會告訴你到底發生了什麼以及按什麼順序)。 – 2013-02-25 18:04:55

+0

@BrianRoach當然,我可以使用debuger,我也試過javap -v -c B.class。但是每次當我看到java開發人員或面試問題的這些任務時,我都會嘗試預測輸出並理解它,爲什麼它會像這樣工作,以及如果稍微修改代碼會發生什麼情況。逐步進行並沒有解釋執行過程的規則和原因。 – INlHELL 2013-02-27 09:58:32

回答

8

的順序是:

  1. 首頁 - > 「你好」
  2. 首頁 - >新B()
  3. B() - > Main() - > b.printVariable() - >設置變量
  4. 返回初始值ng B,所以變量= null發生。

所以基本上,超級對象Main()是在類B的任何初始化事件之前構造的。這意味着變量= null會在稍後發生。這是有道理的,否則B可能會破壞Main的初始化。

Joshua Bloch在他有效的java書中介紹了很多有關如何危險繼承得到正確的好地方,我會推薦它。

+0

非常感謝你的解釋,也非常感謝你提到的這本書,我會再仔細閱讀一次。 – INlHELL 2013-02-27 10:10:59

2

首先,您需要了解當您編寫variable = null;時會發生什麼。該代碼何時執行。這基本上決定了輸出。

在開始之前,我還要提到,當您創建一個對象class B時,主類的printVariable()函數不會被調用。相反,總是會調用B的printVariable()

記住這一點,當你有variable = null時,B的構造函數的執行將開始。將調用第一個Main(),它將調用printVariable()方法。最後,variable=null,將被稱爲覆蓋variable變量。

在另一種情況下,如果您未初始化variable=nullprintVariable()函數設置的variable不會被覆蓋,因此您會得到您所期望的。

總之,這是語句的執行順序,當你做new B()

Main()  //super constructor 
    B#printVariable() 
    initializtion of variables in B's constructor (if any) [i.e. variable=null, if present] 
+0

非常感謝你,你的解釋完全澄清此代碼。我沒有得到,有可能以這種方式初始化字段: super_class-> method_of_child_class-> field_of_child_class 並且該字段可能會在兒童初始化過程中被覆蓋(如果字段不爲空)類。 – INlHELL 2013-02-27 10:25:33

1

這是一個不錯的練習!但問初級開發人員這不是一個公平的問題。這是一個老年人。

public Main(String something){ 
printVariable(); 
} 

如果這個人會回答會發生什麼,然後取出參數,並要求原始的問題:但是,爲了使這個文本的技術面試過程中非常有用,我會通過添加參數傳遞給主要的構造函數修改了它。如果這個人不回答 - 就沒有必要繼續 - 他/她是初中。

您還可以刪除在B級受保護的資格,並詢問如果你有一個目標,不僱傭這個人:)