2009-06-16 45 views
15

如果在完成調用期間保存對當前對象的引用,會發生什麼情況?例如:完成期間對象引用

class foo { 
    ... 
    public void finalize() { 
     bar.REFERENCE = this; 
    } 
} 

對象是垃圾收集的,還是不是?當您稍後嘗試訪問bar.REFERENCE時會發生什麼?

+4

+1因爲這是一個很好的問題,但我希望這只是一個智力練習。 ;) – 2009-06-16 16:41:58

+0

不用擔心,它是:) – 2009-06-16 17:04:17

回答

11

該對象不是垃圾收集。這被稱爲「對象復活」。

你必須要小心,一旦終結被稱爲GC將不會再次調用它,就像.NET一些enviroments你可以重新註冊終結,但我不知道有關Java

6

這種事情是爲什麼通常不鼓勵使用finalize()的原因。

1

可以在foo實例上明確調用finalize()方法,也可以在垃圾收集器試圖回收該對象佔用的存儲時調用該方法。

如果bar是一個有效的實例,它將REFERENCE字段設置爲foo實例。從垃圾收集器的角度來看,這增加了foo的引用計數。

如果異常的finalize()方法內引發(例如,諸如一個NullPointerException由於barnull),則最終處理簡單地終止。

N.B.正如其他人指出的那樣..你的例子絕對是要避免的。

9

如果你絕對必須復活對象,這篇JavaWorld文章建議創建一個新實例,而不是復活正在最終確定的實例,因爲如果實例正在最終確定再次有資格收集,它將被簡單地收集(終結器將不會運行再次)。

0

因爲Java是一種安全的語言和平臺,所以內存不會被釋放。還有相關聯的PhantomReference將不會按照他們的ReferenceQueue s排隊。 VM只會在對象上調用finalize一次。 JVM規範中有一個很好的狀態圖。

通常,如果您確實使用了終結器,則應該將聲明保留爲@Override protected void finalize() throws Throwable,以免干擾API。更有效的方法是使用守衛的終結者,如Effective Java 1st Ed。

當普林斯頓的一個小組用它從不可信的代碼構建一個自定義的ClassLoader時,這個特殊的技巧觸及了聖何塞水星的頭條新聞。儘管規範稍微收緊了一些(在構建器可以調用之前,構造函數必須正常完成執行 - 在Java SE 6中實現的J2SE 5.0中指定),但這仍然是一個問題區域。如果你正在設計一個API,確保敏感類不能是子類,併爲自己節省很多的痛苦。

相關問題