这按预期工作,我不认为finalize()
方法的处理方式与 Java 中的任何其他方法不同。可以认为有点不同的是finalize()
方法通常仅由 JVM 垃圾收集器本身调用,如JavaDoc http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#finalize%28%29:
当垃圾收集确定不再有对该对象的引用时,由该对象的垃圾收集器调用。
另请注意,Josh Bloch 强烈警告不要在:
终结器是不可预测的,通常很危险,而且通常是不必要的。它们的使用可能会导致行为不稳定、性能不佳和可移植性问题。终结器有一些有效的用途……但根据经验,您应该避免使用终结器。
考虑以下示例,该示例与您的示例类似:
具有重写的基类finalize()
method.
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 方法查找(用非常简单的术语来说)是在当前类中查找任何方法,如果没有,则攀爬类层次结构,直到找到所需的方法。在上面的例子中,当foo()
方法被调用SubClass
对象,即SubClass
类包含方法定义,以便使用实现,并且类层次结构不会向上爬。当。。。的时候finalize()
方法被调用(因为System.gc()
已被请求),该方法将首先在SubClass
类,但因为它不包含实现finalize()
它的父级(BaseClass
) 被搜索。BaseClass
确实包含一个实现finalize()
因此使用它,并将一行打印到标准输出。
现在考虑一个覆盖的子子类finalize()
again:
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
class:
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
不是决定所使用的方法实现的因素 - 它是实际的类型object引用者sc