終結方法(finalizer)通常是不可預測的,也是很危險的,一般情況下是不必要的。使用終結方法會導致行為不穩定、降低效能,以及可移植性問題。
在Java中完成這樣的工作主要是依靠
try-finally機制來協助完成的,然而Java中還提供了另外一種被稱為finalizer的機制,使用者僅僅需要重載Object對象提供的finalize方法,這樣當JVM的在進行記憶體回收時,就可以自動調用該方法。但是由於對象何時被垃圾收集的不確定性,以及finalizer給GC帶來的效能上的影響,因此並不推薦使用者依靠該方法來達到關鍵資源釋放的目的。比如,有數千個圖形控制代碼都在等待被終結和回收,可惜的是執行終結方法的線程優先順序要低於普通的工作者線程,這樣就會有大量的圖形控制代碼資源停留在finalizer的隊列中而不能被及時的釋放,最終導致了系統運行效率的下降,甚至還會引發JVM報出OutOfMemoryError的錯誤。
Java的語言規範中並沒有保證該方法會被及時的執行,甚至都沒有保證一定會被執行。即便開發人員在code中手工調用了 System.gc 和 System.runFinalization 這兩個方法,這僅僅是提高了finalizer被執行的幾率而已。還有一點需要注意的是,被重載的finalize()方法中如果拋出異常,其棧幀軌跡是不會被列印出來的。在Java中被推薦的資源釋放方法為,提供顯式的具有良好命名的介面方法,如 FileInputStream.close() 和 Graphic2D.dispose() 等。然後使用者在finally區塊中調用該方法,見如下代碼:
public void test() { FileInputStream fin = null; try { fin = new FileInputStream(filename); //do something. } finally { fin.close(); }} 在實際的開發中,利用finalizer又能給我們帶來什麼樣的協助呢。見下例:
public class FinalizeTest { //@Override protected void finalize() throws Throwable { try { //在調試過程中通過該方法,列印對象在被收集前的各種狀態, //如判斷是否仍有資源未被釋放,或者是否有狀態不一致的現象存在。 //推薦將該finalize方法設計成僅在debug狀態下可用,而在release //下該方法並不存在,以避免其對運行時效率的影響。 System.out.println("The current status: " + _myStatus); } finally { //在finally中對超類finalize方法的調用是必須的,這樣可以保證整個class繼承 //體系中的finalize鏈都被執行。 super.finalize(); } }}