【Effective Java】避免使用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方法,或采用终结方法守卫者方法

猜你喜欢

转载自blog.csdn.net/xl890727/article/details/80082604