避免使用finalize

閱讀經典——《Effective Java》03

Java語言包中的Object類是所有類的祖先。該類提供了諸如equals、hashCode、toString、clone、finalize等方法。本文重點討論finalize方法,其余將在后面文章中陸續出現。

finalize方法

Java文檔對finalize方法的解釋如下。

當對象不再擁有可到達的引用時,垃圾回收器在回收該對象的空間前調用它的finalize方法。子類可在該方法中釋放占用的系統資源或執行其它清理工作。

通常,我們會用finalize方法關閉已經打開的文件,但是請注意,這是嚴重錯誤!

finalize方法的缺點在于不保證會被及時的執行,甚至根本不保證一定會執行。很多時候直到程序終止仍然有不可達對象的finalize方法沒有被執行。因此,在finalize中關閉文件很可能失敗。

另外,System.gc()System.runFinalization()只是增加finalize被執行的機會。唯一聲稱保證finalize方法在程序終止前執行的是System.runFinalizersOnExitRuntime.runFinalizersOnExit。但它們有致命的缺陷,已經被廢棄了。

finalize中拋出的異常會被忽略,以至于程序員無法得知它是否成功執行。

finalize會導致嚴重的性能損失(在原書作者的機器上,有finalize方法時創建和銷毀對象慢了大約430倍)。

因此,鑒于finalize方法有如此多的缺點,我們大部分時候應當避免使用。但仍有兩種合理用法。

用途一:配合顯式終止方法

仍然是關閉文件的問題,正確的做法是提供一個顯式終止方法,通常稱為close,并要求客戶端程序手動調用。該方案的典型例子是InputStreamOutputStream、java.sql.Connection,這些類都提供了close方法以關閉相應的文件或數據庫連接。

但是一些不靠譜的程序員通常會忘記調用close方法,因此可以在finalize中再次檢查并調用close方法,以降低資源泄漏的可能性。(注意,由于finalize并不可靠,該方案只能降低資源泄漏的可能性而無法完全消除。)在InputStream、OutputStream、java.sql.Connection這些類中也的確是這樣做的,大家可以自己查看源碼。

用途二:終結方法守衛者

如果子類打算重寫父類的finalize方法,我們推薦以下面的方式重寫。這樣做可以保證即使子類的終結過程拋出異常,父類的finalize方法也會得到執行。

@Override
protected void finalize() throws Throwable {
  try {
    //Finalize subclass state
  } finally {
    super.finalize();
  }
}

但是,假如子類沒有在重寫的finalize方法中調用super.finalize(),那么父類的finalize方法將永遠不能得到調用。站在父類的角度上,要想防范這樣粗心或者惡意的子類,可以使用終結方法守衛者。

終結方法守衛者是在父類中的一個匿名內部類實例,該內部類覆寫finalize方法,并在其中做父類需要的終結操作。

public class Foo {
  private final Object finalizerGuardian = new Object() {
    @Override
    protected void finalize() throws Throwable {
      //Finalize outer Foo object
    }
  };
  //...
}

現在,即使Foo的子類覆寫了finalize方法,也不會影響Foo的終結操作,因為finalizerGuardian一直存在。當子類對象不可達時,finalizerGuardian同樣不可達,它們都會進入垃圾回收器的回收隊列。因此可以保證父類的終結操作不被忽略。

關注作者文集《Effective Java》,第一時間獲取最新發布文章。

參考資料

Java終結方法的使用(終結守衛者) SamXCode
What's the behaviors of fields when finalize an object? jinge
Java將棄用finalize()方法? Ben Evans

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容

  • 一、終結方法VS析構器 熟悉C++的都知道,析構器是用來回收一個對象所占用資源的常規方法,是構造器所必需的對應物。...
    真愛也枉然閱讀 490評論 0 0
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,729評論 18 399
  • 終結方法的缺點 終結方法(finalizer)是不可預測的,也是很危險的。使用終結方法會導致行為不穩定、降低性能,...
    每天學點編程閱讀 379評論 0 1
  • 這兩天工作太忙了,實在沒時間寫英語干貨文章。 不過明天的文章是關于如何提高英語溝通技巧的,大家可以好好看看。文章比...
    Freedom_Pursuer閱讀 243評論 7 2
  • 野外逢迎少,柴門落葉稠,人閑不掃室,客到始梳頭。 且為烹茶坐,還因看竹留,登臨如有興,更上水邊樓。 ——明·何景明...
    NuIl閱讀 419評論 1 0