簡體   English   中英

在java中初始化實例變量時使用'this'?

[英]Using 'this' when initializing an instance variable in java?

我在IB的API中聲明一個實例變量時已經看過this ,但這似乎是一個壞主意。 被分配工作后,發生this已經完全構造? 有關系嗎?

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

如果它以某種方式工作,它似乎不是一個好主意 - second可用於FirstClass的構造函數? 如果是這樣, SecondClassFirstClass之前構建? 這意味着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. “正確” 以文本順序從其最高超類(即對象)開始初始化所有變量並以此類結束 - 因此,在初始化為3之前, second被初始化(即構造)。
  4. 如果這些“正確”初始化中的任何一個調用另一個方法或另一個構造函數,則調用第一個構造函數之前完成 - 因此在構造FirstClass之前構造並返回second構造函數。
  5. 如果通過實例初始化調用另一個構造函數(例如在第4項中),它將從第1項開始執行相同的過程(內存分配,初始化等)

這樣做的原因很糟糕,“保證”結果可以通過兩種方式改變:

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

因此看起來IB的API會受到這種美味的影響,我現在必須牢記這一點。

感謝Emil H的回答和他對本文的指導,這最終促使我理解上述內容: http//www.artima.com/designtechniques/initializationP.html - 強烈推薦閱讀。

還要感謝Alexander Drobyshevsky在答案中提出了非常相似的觀點。

當然,有時你必須使用它,例如當通過構造函數給出的變量被調用為與實例變量相同時:

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

是的, this (在內部是構造中對象的“指針”)可以在構造函數中使用。

一個愚蠢的例子可能是一個自我引用的類

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

還有更現實的例子。 想象一下,您希望一個類表示一個數學圖,您將使用連接到自身的單個元素進行初始化。

有趣的問題。 在您描述的情況下,當您調用new FirstClass() ,類加載器會查找該類並在未加載它時加載它。 然后它似乎創建了一個FirstClass實例,其中所有字段都有其默認值,例如,second為null,i為0。

然后是類加載器加載SecondClass 創建並初始化SecondClass的實例,將num字段設置為10.然后構造函數調用傳入FirstClass實例(字段具有已初始化到該點的值)。 因此,在構造函數中, SecondClassnum的值將設置為0。

SecondClass構造函數完成后,將對象get分配給FirstClasssecond字段(仍在初始化)。 之后i初始化為3.現在調用FirstClass的構造函數,並為i分配DoSomething()的返回值,在本例中為0。

如需進一步參考,請查看: http//www.artima.com/designtechniques/initializationP.html它給出了對象初始化的描述。

TL; DR所以回答你的問題:

  1. 是的, this可以在初始化實例變量時使用。
  2. 應該避免,因為如果某人移動字段(例如對它們進行排序)可能會改變您的類的行為,這是不可能的。

這有兩種可能的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個參數的構造函數。

希望有所幫助!

起初,這是一個糟糕的方式。 您必須避免使用這些結構:使用未完全初始化的變量。 有時候使用“模板方法”設計模式可能會有所幫助。

正是在你的例子中,在這種情況下,在執行FirstClass構造函數之后,i = 0的結果值; 它取決於FirstClass中i的賦值順序。 如果您通過下一個方式更改分配順序:

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

在FirstClass構造函數執行完后,你得到答案i = 3。

this - 僅引用當前類實例。 它已經存在於您的類實例變量開始初始化時。 首先,所有變量都有其默認值(object為null,int為0等)。 在第二個初始化所有簡單的賦值,如“int i = 3”,之后執行當前類的超級構造函數,最后執行當前類的構造函數。 簡單變量按類中的順序初始化為up,但是你不應該依賴它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM