如果在完成調用期間保存對當前對象的引用,會發生什麼情況?例如:完成期間對象引用
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
對象是垃圾收集的,還是不是?當您稍後嘗試訪問bar.REFERENCE
時會發生什麼?
如果在完成調用期間保存對當前對象的引用,會發生什麼情況?例如:完成期間對象引用
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
對象是垃圾收集的,還是不是?當您稍後嘗試訪問bar.REFERENCE
時會發生什麼?
該對象不是垃圾收集。這被稱爲「對象復活」。
你必須要小心,一旦終結被稱爲GC將不會再次調用它,就像.NET一些enviroments你可以重新註冊終結,但我不知道有關Java
這種事情是爲什麼通常不鼓勵使用finalize()
的原因。
可以在foo
實例上明確調用finalize()
方法,也可以在垃圾收集器試圖回收該對象佔用的存儲時調用該方法。
如果bar
是一個有效的實例,它將REFERENCE
字段設置爲foo
實例。從垃圾收集器的角度來看,這增加了foo
的引用計數。
如果異常的finalize()
方法內引發(例如,諸如一個NullPointerException
由於bar
是null
),則最終處理簡單地終止。
N.B.正如其他人指出的那樣..你的例子絕對是要避免的。
如果你絕對必須復活對象,這篇JavaWorld文章建議創建一個新實例,而不是復活正在最終確定的實例,因爲如果實例正在最終確定再次有資格收集,它將被簡單地收集(終結器將不會運行再次)。
因爲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,確保敏感類不能是子類,併爲自己節省很多的痛苦。
+1因爲這是一個很好的問題,但我希望這只是一個智力練習。 ;) – 2009-06-16 16:41:58
不用擔心,它是:) – 2009-06-16 17:04:17