Java终结者监护人似乎不起作用?

时间:2011-08-12 14:26:41

标签: java finalize

我有一个带有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中获取。

我很困惑。我是否从根本上误解了一些事情?

免责声明:我意识到终结器是危险的,不可取的等等。仍在尝试理解这里的问题。

4 个答案:

答案 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对象仍然可以很强地访问,它也可以收集垃圾。