【Effective Java】條7:避免使用finalize方法

finalize()方法不像C++中的析構,C++中必須使用析構來釋放內存和資源。在Java中,內存通常由GC(垃圾回收器)回收,資源常採用try...finally來完成。

使用finalize方法缺點

  1. 不能保證被執行

    1). 程序被強制終結,不會調用finalize方法
    2). finalize方法執行時拋出異常,不會繼續執行

  2. 不能保證及時被執行

    1). 對時間敏感的任務不能在finalize中執行,譬如文件資源回收

  3. 性能損失

  4. 移植性差
    1). 不同JVM實現的GC不同,導致finalize在不同平臺不一定都能運行

合理用途

  1. 安全網-最後釋放內存和資源保障
    當對象使用者忘記採用try...finaly顯示釋放資源,則finalize方法可作爲最後的保障(可能釋放總比不會釋放要好)。譬如FileInputStramFileOutputStramTimerConnection等中的finalize方法。

  2. 回收本地對等體

    本地對等體:指Java通過JNI調用本地方法,將普通對象委託給本地對象的對象。本地對等體不能被JVM GC回收。

    當本地對等體沒有關鍵資源時可通過GC回收,否則最好顯示終結。

在使用finalize方法時,需要注意的是如果子類重寫了父類的finalize方法,則子類並不會默認調用父類的finalize方法。你需要顯示的調用,如下所示:

@Override
public void finalize() throws Throwable {
    try {
        //子類的finalize實現
    } finally {
        //調用父類的finalize方法
        super.finalize();
    }
}

你也可以採用終結方法守衛者,代碼如下:

public class Parent {

  private Object finalizeGuardian = new Object() {
    @Override
    protected void finalize() throws Throwable {
      System.out.println("Parent Guardian finalize");
    }
  };

  private static void testFinalize() {
    Sub sub = new Sub();
    sub = null;

    System.gc();
  }

  //輸出結果爲:
  //Sub finalize
  //Parent Guardian finalize
  public static void main(String[] args) {
    testFinalize();
  }

}

class Sub extends Parent {
  @Override
  protected void finalize() throws Throwable {
    System.out.println("Sub finalize");
  }
}

總結

  1. 強烈不推薦使用finalize方法;
  2. 萬一必須要使用,注意子類必須顯示調用父類finalize方法,或採用終結方法守衛者方法
發佈了98 篇原創文章 · 獲贊 180 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章