这按预期工作,我认为finalize() 方法与Java 中的任何其他方法没有任何不同。可以认为有点不同的是,finalize() 方法通常仅由 JVM 垃圾收集器本身调用,如JavaDoc 中所述:
当垃圾收集器确定不再有对该对象的引用时,由垃圾收集器对该对象调用。
另请注意,Josh Bloch 强烈警告不要在 Effective Java 中使用终结器:
终结器是不可预测的,通常很危险,而且通常是不必要的。使用它们会导致行为不稳定、性能不佳和可移植性问题。终结器有一些有效用途……但根据经验,您应该避免使用终结器。
考虑下面的例子,它与你的相似:
具有覆盖 finalize() 方法的基类。
public abstract class BaseClass {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("BaseClass finalisation occured");
}
}
一个不覆盖finalize的子类:
public class SubClass extends BaseClass {
public void foo() {
System.out.println("SubClass Foo'd");
}
}
还有一个驱动类,它有一个基本的 main 方法来运行所有东西:
public class Driver {
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.foo();
sc = null;
System.gc();
}
}
我们得到的输出如下:
SubClass Foo'd
BaseClass finalisation occured
Java 方法查找(用非常简单的术语)发生的事情是在当前类中查找任何方法,如果没有,则爬上类层次结构,直到找到所需的方法。在上面的示例中,当在SubClass 对象上调用foo() 方法时,SubClass 类包含方法定义,以便使用实现,并且类层次结构不会向上爬升。当调用finalize() 方法时(因为已请求System.gc()),该方法将首先在SubClass 类中查找,但由于它不包含finalize() 的实现,其父类(@987654337 @) 被搜索。 BaseClass 确实包含 finalize() 的实现,因此被使用,并将一行打印到标准输出。
现在考虑一个再次覆盖finalize() 的子类:
public class OverridenSubClass extends SubClass {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Overriden finalize called, which calls super's finalize first");
}
}
还有一个稍作修改的Driver 类:
public class Driver {
public static void main(String[] args) {
OverridenSubClass sc = new OverridenSubClass();
sc.foo();
System.out.println(sc.toString());
sc = null;
System.gc();
System.exit(0);
}
}
产生以下输出:
SubClass Foo'd
finalize.OverridenSubClass@7150bd4d
BaseClass finalisation occured
Overriden finalize called, which calls initial finalize first
希望这符合预期。这里唯一需要注意的是:
- 我们不会在任何类中覆盖
toString(),因此使用了 Object.toString() 实现。
- 变量
sc 的类型不是决定使用的方法实现的因素——它是sc 引用的实际对象 的类型