这按预期工作,我认为该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 方法查找(用非常简单的术语)发生的情况是在当前类中查找任何方法,如果没有,则爬升类层次结构,直到找到所需的方法。在上面的示例中,当在对象foo()
上调用方法时,类包含方法定义以便使用实现,并且类层次结构不会向上爬升。当方法被调用时(因为 a已经被请求),该方法将首先在类中查找,但由于它不包含其父 ( ) 的实现,因此会被搜索。确实包含使用的so that 的实现,并将一行打印到标准输出。SubClass
SubClass
finalize()
System.gc()
SubClass
finalize()
BaseClass
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