终结方法(finalizer) 通常是不可预测的,也是很危险的,一般情况下是不必要的.
不要把终结方法当做是C++中的析构器的对应物:
C++ 需要析构器来与构造器对应,来回收对象所占的资源.
Java 中内存资源由垃圾收集器处理, 非内存资源由 try-finally 处理.
终结方法的缺点:
- 不稳定: 不能保证会被及时执行
- 可移植性低:及时执行终结算法是垃圾回收算法的一个主要功能, 不同的JVM的实现中会大相径庭.
- 延迟终结过程: 一个类中的终结方法,可能会随意的延迟实例的回收过程.(终结方法线程的优先级低)
- Java 语言规范不仅不保证终结方法会被及时执行,而且根本不保证他们会被执行.(不应该依赖终结方法来更新重要的持久状态) System.gc 和 System.runFinalization 两个方法仅仅是增加了终结方法被执行的机会,但并不保证终结方法一定会被执行.
- 非常严重的性能损失: 创建和销毁普通对象: 5.6ns, 有终结方法的对象: 2400ns, 慢了大约340倍
如果 类的对象中封装的资源 (文件或者线程)确实需要终止,可以采用: 显式的终止方法 + try-finally
显式的终止方法,例如 InputStream, OutputString 和 java.sql.Connection 上的 close 方法.
在finally 里调用显式的终止方法,可以保证即使在使用对象时有异常抛出,该终止方法也会执行.
Foo foo = new Foo(...);
try {
// Do what must be done with foo
...
} finally {
foo.terminate(); // Explicit termination method
}
终结方法的两种合法用途:
- 当对象的所有者忘记调用显式终止方法时,终结方法可以充当"安全网".(延迟释放好过因为代码bug造成永远不释放, 需要考虑这种额外的保护是否值得付出额外的代价)
- 处理本地对等体(native peer),这不是普通的对象, 垃圾回收器不会知道它的存在,GC只会回收Java对等体.
注意:终结方法链不会被自动执行.如果类有终结方法,并且子类覆盖了终结方法, 子类的终结方法就必须手动调用超类的终结方法.
@override
protected void finalize() throws Throwable {
try {
... // Finalize subclass state
} finally {
super.finalize();
... //
}
}
如果子类覆盖了超类的终结方法,但是忘了调用超类的终结方法,那么超类的终结方法将永远不会被调用到.
总之,除非是作为安全网,或者为了终结非关键的本地资源,否则请不要使用终结方法.
如果使用了终结方法,记得super.finalize()