程序員都知道“初始化”的重要性,但通常忘記清除的重要性。畢竟,誰需要來清除一個int呢?但是對於庫來說,用完後簡單地“釋放”一個對象並非總是安全的。當然,Java可用垃圾收集器回收由不再使用的對象占據的內存。現在考慮一種非常特殊且不多見的情況。假定我們的對象分配了一個“特殊”內存區域,沒有使用new。垃圾收集器只知道釋放那些由new分配的內存,所以不知道如何釋放對象的“特殊”內存。為解決這個問題,Java提供了一個名為finalize()的方法,可為我們的類定義它。在理想情況下,它的工作原理應該是這樣的:一旦垃圾收集器准備好釋放對象占用的存儲空間,它首先調用finalize(),而且只有在下一次垃圾收集過程中,才會真正回收對象的內存。所以如果使用finalize(),就可以在垃圾收集期間進行一些重要的清除或清掃工作。
但也是一個潛在的編程陷阱,因為有些程序員(特別是在C++開發背景的)剛開始可能會錯誤認為它就是在C++中為“破壞器”(Destructor)使用的finalize()——破壞(清除)一個對象的時候,肯定會調用這個函數。但在這裡有必要區分一下C++和Java的區別,因為C++的對象肯定會被清除(排開編程錯誤的因素),而Java對象並非肯定能作為垃圾被“收集”去。或者換句話說:
垃圾收集並不等於“破壞”!
若能時刻牢記這一點,踩到陷阱的可能性就會大大減少。它意味著在我們不再需要一個對象之前,有些行動是必須采取的,而且必須由自己來采取這些行動。Java並未提供“破壞器”或者類似的概念,所以必須創建一個原始的方法,用它來進行這種清除。例如,假設在對象創建過程中,它會將自己描繪到屏幕上。如果不從屏幕明確刪除它的圖像,那麼它可能永遠都不會被清除。若在finalize()裡置入某種刪除機制,那麼假設對象被當作垃圾收掉了,圖像首先會將自身從屏幕上移去。但若未被收掉,圖像就會保留下來。所以要記住的第二個重點是:
我們的對象可能不會當作垃圾被收掉!
有時可能發現一個對象的存儲空間永遠都不會釋放,因為自己的程序永遠都接近於用光空間的臨界點。若程序執行結束,而且垃圾收集器一直都沒有釋放我們創建的任何對象的存儲空間,則隨著程序的退出,那些資源會返回給操作系統。這是一件好事情,因為垃圾收集本身也要消耗一些開銷。如永遠都不用它,那麼永遠也不用支出這部分開銷。