我有一个带有finalize()方法的伸缩构造函数的超类。为了防止子类忘记调用super.finalize,我编写了一个终结器监护人(EJ Item 7)。
public class Super {
public Super() {}
{
Object finalizerGuardian = new Object() {
@Override
protected void finalize() {
System.out.println("Finalizer guardian finalize");
Super.this.finalize();
}
};
}
protected void finalize() {
System.out.println("Super finalize");
}
}
这是一个样本子类 -
public class Sub extends Super {
public Sub() {}
protected void finalize() {
System.out.println("Sub finalize");
}
public static void main(String[] args)
throws InterruptedException {
if (1 == 1) {
Sub s1 = new Sub();
}
Runtime.getRuntime().gc();
Thread.sleep(10000);
}
}
当s1对象超出范围时,终结器监护人的finalize()被调用,我从子类的finalize方法获得SYSO,但从未从super的finalize中获取。
我很困惑。我是否从根本上误解了一些事情?
免责声明:我意识到终结器是危险的,不可取的等等。仍在尝试理解这里的问题。
答案 0 :(得分:8)
Effective Java的终结器监护人应该自己执行必要的终结逻辑(例如,调用执行实际终结的Super
方法),而不是调用finalize()
方法,因为在你的情况下{{ 1}}实际上从子类调用overriden方法。
另请注意,终结者监护人应该是班级的一个领域:
Super.this.finalize();
答案 1 :(得分:2)
您正在重载Super.finalize()
中的Sub
方法。这就是它没有被召唤的原因。
因此,当您在“finalizerGuardian
”中致电Super.this.finalize();
时,您实际上正在呼叫Sub.finalize()
。
答案 2 :(得分:2)
其他人已经说过动态调度是你的问题。但是据我所知,你的代码还有一个主要的错误:你的finalizerGuardian只在初始化块中定义,这意味着只要对象被初始化,对象就会超出范围并且可以进行GC。
即使您修复了第一个问题(通过在类中定义处理终结内容的最终方法),您仍然需要将finalizerGuardian保存在实例变量中。答案 3 :(得分:2)
Super.finalize()
未被调用,因为Sub会覆盖它。尝试添加Super._finalize()
方法并从Super.finalize()
和终结器监护人处调用它。
另外,我认为finalizerGuardian
必须是Super
的字段。否则,即使Super对象仍然可以很强地访问,它也可以收集垃圾。