2013-12-16 49 views
6

我認爲這個問題的具體用途如下,但它更加通用化。在構造函數結束之前如何引用/處理「this」?

我有一個自定義JFrame類,它也可以作爲其組件的ActionListener。所以我的構造看起來像下面這樣:

private JButton myButton; 

public MyCustomFrame() { 
    super(); 
    myButton.addActionListener(this); 
    // ... more stuff 
} 

我的問題是,這是如何在幕後工作?如果構造函數是「創建」this引用的對象,那麼在構造函數返回之前如何使用this?代碼編譯和工作完全正常(據我所知),因此該對象在某種意義上必須已經「存在」,但我擔心這可能會導致無法預料的問題。通過對addActionListener()的「部分構建」引用(或者只是通常對其執行任何邏輯)有沒有任何危險?還是有一些幕後的魔法發生讓我安全?

例如,那些沒有默認值並且必須由構造函數提供的東西呢?如果我聲明瞭private final String SOME_VALUE;,我知道這應該默認爲null,但該對象不應該完全形成,直到常量在構造函數中提供一個值。那麼,儘管是最終的,參考文獻可能會改變價值嗎?

+0

沒有直接連接到你的問題,但它可以爲你的目的http://stackoverflow.com/a/3404369/2350145 –

回答

9

即Java語言規範指定的instance creation

步驟[...]

接下來,空間分配給新的類實例。如果 沒有足夠的空間來分配對象,則通過拋出 OutOfMemoryError,類 實例創建表達式的評估突然完成。

新對象包含在 中聲明的指定類類型及其所有超類的所有字段的新實例。 當創建每個新字段 實例時,它將被初始化爲其默認值(§4.12.5)。

接下來,對構造函數的實際參數進行評估, 從左到右。如果任何參數評估突然完成, 右側的任何參數表達式都不計算,並且類 實例創建表達式由於相同的原因突然完成。

接下來,調用指定類類型的選定構造函數。 這導致爲類類型的每個超類 調用至少一個構造函數。此過程可以通過顯式的 構造函數調用語句(第8.8節)指導,並在 第12.5節中詳細介紹。

因此,當構造函數(這是一個方法)被調用時,您的實例將以默認值存在。

對於final字段,如果您嘗試訪問它們,那麼它們顯示爲默認值。例如

public class Driver { 

    public static void main(String[] args) { 
     new Driver(); 
    } 

    final int value; 

    public Driver() { 
     print(this); 
     value = 3; 
    } 

    static void print(Driver driver) { 
     System.out.println(driver.value); 
    } 

} 

將打印0.如果我能找到它,我會馬上回到JLS條目。

我找不到更具體的東西,那麼上面是什麼。也許在4.12.4. final Variables

最後一個變量只能被分配一次。

您可以認爲默認初始化會將該值設置爲0或null,並且分配會改變它。

+0

什麼東西沒有默認值,必須*提供*的構造函數?例如,如果我有'私有最終字符串SOME_VALUE;'聲明,我明白這應該默認爲'null',但該對象不應該完全形成,直到常量在構造函數中提供一個值。那麼參考文獻,儘管是「最終」,可能會有變化的價值? (我會將此添加到問題中。) – asteri

+0

@Jeff我試圖編譯一個程序,在分配final字段之前釋放'this'引用,它是默認值(0或'null')。 JLS中一定有這方面的內容,我只需要找到它。 –

+0

我懷疑規格說什麼,因爲它是緊急行爲。該字段尚未由構造函數分配,因爲構造函數的代碼照常按順序運行。在分配任何變量(final或not)之前,你泄漏'this'並且Java不能奇蹟般地知道你將要在那裏放置什麼值。 –

4

一旦你調用你的構造函數,你的對象從一開始就已經存在,並且你只是用值填充它。

如果傳遞對象的方法嘗試使用尚未在構造函數中聲明的值,則會帶來危險。


你也想避免你的構造函數(和其他方法爲此事)作出這樣的方式構造的用戶不會期望。

如果實例化對象的人沒有理由期望構造函數自動將該對象綁定到按鈕,那麼也許你不應該那樣做。

1

this在構造函數完成之前確實存在。但是,在構造函數完成之前允許引用this以逃避對象可能會帶來危險。

如果您將this引用傳遞給假設對象已完全形成並準備就緒的方法,該怎麼辦?也許這對你的對象來說很好,但在很多情況下,這可能是危險的。允許其他方法在準備好使用之前訪問對象會對您的程序能夠可靠運行造成嚴重威脅。

1

你是完全正確的,這是一件壞事,因爲this可能只在您使用它時被部分初始化。

這就是爲什麼許多編譯器會給出警告。

0

不要將它從構造函數中轉義出來,因爲如果另一個線程讀取了構造尚未完成的實例的變量,線程可能會讀取意外的值。

一個例子如下。

public class A { 
    private final int value; 
    public A(int value) { 
    this.value = value; 
    new Thread(new Runnable() { // this escape implicitly 
     public void run() { 
     System.out.println(value); 
     } 
    }).start(); 
    } 
    public static void main(String[] args) { 
    new A(10); 
    } 
} 

該程序可能會顯示Java存儲器模型規範以外的值。

相關問題