如果程序依賴於終結方法被執行的時間點,那麼這個程序的行爲在不同的JVM實現中會大相徑庭。Java語言規範不僅不保證終結方法會被及時的執行,而且根本不保證他們會被執行。不應該依賴終結方法來更新重要的持久狀態。
不要被System.gc和System.runFinalization這兩個方法所誘惑,他們確實增加了終結方法被執行的機會,但是他們不保證終結方法一定被執行。唯一聲稱保證終結方法被執行的方法是System.runFinalizersOnExit,以及他臭名昭著的孿生兄弟Runtime.runFinalizersOnExit。這兩個方法都有致命的缺陷,都被廢棄了。使用終結方法有一個非常嚴重的(Severe)性能損失。提供一個顯示終止的方法來終止一些必要的資源。
顯示終止方法的典型例子是InputStream、OutputStream和java.sql.Connection上的close方法。
另一個例子是java.util.Timer上的cancel方法,它執行必要的狀態改變,使得與Timer實例相關聯的該線程溫和的終止自己。
java.awt中的例子還包括Graphics.dispose和Window.dispose。
Image.flush,他會釋放所有與Image實例相關聯的資源,但是該實例仍然處於可用的狀態,如果有必要的話,會重新分配資源。
總結:
除非作爲安全網,或者是爲了終止非關鍵的本地資源,否則請不要使用終結方法。在這些很少見的情況下,既然使用了終結方法,就要記住調用super.finalize。如果用終結方法作爲安全網,要記得記錄終結方法的非法用法。最後,如果需要吧終結方法與公有的非final類關聯起來,請考慮使用終結方法守護者,以確保即使子類的終結方法未能調用super.finalize,該終結方法也會被執行。
@Override
protected void finalize() throws Throwable {
try{
...//Finalize subclass state
} finally {
super.finalize();
}
}
demo:
class A {
B b;
public A(B b) {
this.b = b;
}
@Override
public void finalize() {
System.out.println("A finalize");
C.a = this;
}
}
class B {
String name;
int age;
public B(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public void finalize() {
System.out.println("B finalize");
}
@Override
public String toString() {
return name + " is " + age;
}
}
class C {
static A a;
}
public class Main {
public static void main(String[] args) throws Exception {
A a = new A(new B("allen", 20));
a = null;
System.gc();
Thread.sleep(5000);
System.out.println(C.a.b);
}
}