2013-05-17 70 views
3

我看過this在IB的API中聲明實例變量時使用,但這似乎是一個壞主意。保證在this已完全構建後保證分配任務?有關係嗎?在java中初始化一個實例變量時使用'this'?

我認爲實例變量是在構造函數之前初始化的,因爲它們可以被構造函數使用。如果使用this,是否有一些例外情況?

如果它以某種方式起作用,它似乎不是一個好主意 - second可用於FirstClass的構造函數嗎?如果是這樣,SecondClass之前構造FirstClass?這意味着num結果是3而i是10?或者會有運行時錯誤?任何一種方式都有保證嗎?

public class FirstClass { 

    SecondClass second = new SecondClass(this); 
    public int i = 3; 

    FirstClass(){ 
     i = second.DoSomething(); 
    } 
} 

public class SecondClass{ 

    private int num = 10; 

    SecondClass(FirstClass first){ 
     num = first.i; 
    } 
    public int DoSomething(){ 
     return num; 
    } 
    ... 
} 

我想認爲IB有一個非常堅實的開發團隊,並且知道他們在做什麼。你怎麼看:

  1. 可以用this初始化實例變量嗎?
  2. 應該這樣做嗎?

編輯

答案是肯定有保證的結果(現在 - 但閱讀...),但沒有它不應該做的,因爲它容易在不經意間更改代碼可以改變這個'保證'的結果。

我現在知道,構造一個新的對象時(如FirstClass)的JVM:

  1. 分配內存給這個類的所有實例變量和它的所有超。
  2. 初始化所有使用默認值
  3. 「正確」初始化所有變量在文本順序從最高超開始(即對象),並用這個類完成變量 - 所以second被初始化(即構造)之前我被初始化爲3
  4. 如果這些「正確的」初始化的調用另一個方法或另一種構造,這樣做是前的第一個構造函數被調用 - 所以second構造和之前的FirstClass構造正在運行返回。
  5. 如果另一個構造是通過實例的初始化調用(如第4項),它經歷了同樣的過程,從項目1(內存分配,初始化等)

之所以這樣做是不好的是, 「保證」結果可以以兩種方式發生變化:

  1. 如果源代碼順序改變(例如,如果是i之前second初始化構造)的結果將改變。不容易注意到這一點。
  2. 如果有人將我們的班級(或班級)劃分爲子類,他們可能不會意識到這種微妙的平衡,並可能在覆蓋時改變影響結果的因素。

因此,看起來IB的API遭受了這種美味,我現在必須牢記在心。

感謝埃米爾H公司的回答和他的方向這篇文章最終導致我我的理解之上:http://www.artima.com/designtechniques/initializationP.html - 這是強烈建議閱讀。

同樣感謝Alexander Drobyshevsky在他的回答中提出了非常相似的觀點。

+0

難道你不能簡單地測試一下,看看結果? –

+0

當然,有一次。但是,我怎麼知道它不是隨機的競爭條件,可能會偶爾表現不同?我想知道是否有任何確定性 - 如果是的話,是否可以使用,或者是否應該由於「風格」原因而避免。 – Ben

回答

0

有趣的問題。在你描述的情況下會發生什麼情況是,當你調用new FirstClass()時,類加載器會查找該類並在它尚未加載時加載它。然後它似乎創建一個FirstClass的實例,其中所有的字段都有其默認值,例如第二爲空並且i是0。

然後,它類加載器加載SecondClassSecondClass的一個實例被創建並初始化,其將num字段設置爲10.然後,構造函數get的被稱爲在FirstClass實例中傳遞(字段具有已經被初始化到該點的值)。所以在構造函數中中的num的值將被設置爲0。

SecondClass構造函數完成後,對象get被分配到FirstClass(仍在初始化中)的second字段。之後i被初始化爲3.現在的FirstClass GET的構造函數調用,我被分配DoSomething()返回值在這種情況下將是0

備查你可以看看:http://www.artima.com/designtechniques/initializationP.html 它給出了一個說明對象的初始化。

TL; DR 因此,要的answere您的問題:

  1. 是,this可以初始化實例變量時使用。
  2. 應該避免,因爲如果有人移動字段(例如排序)可能會改變你的類的行爲,這是不可預料的。
+0

偉大的文章,它幫助我瞭解它如何工作,所以我選擇你的答案 - 我仍然有<15代表所以不能upvote呢。 – Ben

0

是,this(內部是一個「指針」,以在構造中的物體)可以在構造函數中使用。

愚蠢的例子可能是一種自我闖民宅類

class MySelf { 
    Myself _me; 
    public MySelf() { _me = this; } 
} 

還有更多現實的例子。想象一下,你想要一個類來表示一個數學圖,你會用一個連接到它自己的元素初始化。

+0

這是「這個轉義構造函數」的問題 - 它可以被其他線程在完成構建之前使用,這可以(也應該)避免例如通過使用返回完整構造實例的靜態工廠方法。我想知道在變量聲明中使用'this'時是否與構造函數不同。有兩個問題:是否可以完成(以及影響)?是否應該這樣做? – Ben

+0

問題是關於初始化實例valiables時使用'this',而不是關於它在構造函數中的用法... –

1

當然,有時你必須利用這一點,例如當通過構造函數給出一個變量被稱爲同一個實例變量:

int count; 
public Test(int count){ 
    this.count = count; 
} 
+0

對不起,無論我做什麼,代碼都不會格式化...... – desperateCoder

+0

@Maroun Maroun:你是如何格式化它?我試了很多... – desperateCoder

0

這在Java中有兩種可能的變體;首先,當你想引用一個全局變量(來自外部的範圍)。例如:

class First { 

    private int x; 

    public void setX(int x) { 
    this.x = x; // outer x is equal to the parameter 
    } 

} 

另一個用法,就是引用當前對象的構造函數。例如:

public Color { 

    private int red, green, blue; 

    public void Color(int r, int g, int b) { 
    red = red; 
    green = g; 
    blue = b; 
    } 

    public void setColor(int r, g, b) { 
    this(r,g,b); 
    } 

} 

通過用3個參數調用這個(1,2,3)來告訴編譯器你希望引用帶3個參數的構造函數。

希望有幫助!

0

起初,這是一個不好的方法。你必須避免這些結構:使用不完全初始化的變量。 有些時候,使用「模板方法」設計模式可能會有幫助。對於你的例子,在這種情況下,在FirstClass構造函數執行後,i = 0的結果值是正確的。它取決於FirstClass中的i的賦值順序。如果您通過下一步更改分配順序:

public int i = 3; 
SecondClass second = new SecondClass(this); // just order changed 

您在FirstClass構造函數執行後得到答案i = 3。

這是 - 僅對當前類實例引用。它在你的類實例變量開始初始化的時候已經存在了。起初,所有變量都有其默認值(對象爲null,int爲0等)。其次,初始化所有簡單的賦值,例如「int i = 3」,然後執行當前類的超級構造函數,最後執行當前類的構造函數。簡單的變量是通過類中的順序來初始化的,但是你不應該依賴它。

+0

謝謝,如果可以的話,我會幫你提供幫助,但我的聲望還不到15。 – Ben