Java中的“finalizer guardian”是如何工作的?

16

“终结器守卫” [《Effective Java》第30页] 是如何工作的?

您使用过它们吗?它解决了什么具体问题吗?


没用过它。也许是因为我不写终结器。 - duffymo
1个回答

20

它解决了子类忘记调用超类finalize方法的问题。该模式通过向您的超类附加一个具有覆盖finalize的额外实例来工作。这样,如果超类超出范围,附加的实例也会超出范围,从而触发其finalize的执行,进而调用封闭类的finalize

下面是展示守护模式的简短代码段:

public class Parent {

    public static void main(final String[] args) throws Exception {
        doIt();
        System.gc();
        Thread.sleep(5000); //  5 sec sleep
    }

    @SuppressWarnings("unused")
    private final Object guardian = new Object() {
        @Override protected void finalize() {
            doFinalize();
        }
    };

    private void doFinalize() {
        System.out.println("Finalize of class Parent");
    }

    public static void doIt() {
        Child c = new Child();
        System.out.println(c);
    }

}

class Child extends Parent {

    // Note, Child class does not call super.finalize() but the resources held by the
    // parent class will still get cleaned up, thanks to the guardian pattern
    @Override protected void finalize() {
        System.out.println("Finalize of class Child");
    }

}

2
但是,当到达父类被GC(垃圾回收)的时候,由于匿名类持有对父类的引用,而且父类也通过实例字段链接持有对匿名类的引用,因此父类将无法被GC。 那么由于这种循环引用,父类和匿名类如何才能符合垃圾回收的条件呢? - Geek
2
@Geek:Java拥有一个非常棒的垃圾回收器,不会被循环引用所困扰。更多信息请参见这里 - Sanjay T. Sharma
1
Parent.finalize()是否应该调用Parent.doFinalize()?如果Child调用super.finalize()或者Parent的实例被finalize,那么这样做会导致doFinalize()被调用两次,对吗? - Michael Anderson
@MichaelAnderson:+1;你说得对,公共类Parent不应该覆盖finalize方法。已编辑。 - Sanjay T. Sharma
@SanjayT.Sharma,关于“*注意,子类不调用super.finalize()*”,然而,为什么会发生这种情况呢?难道所有子类终结器都不需要遵守调用super finalize的契约吗? - Pacerier
@Pacerier:不,它不是合同的一部分(只是另一个被覆盖的方法),并且拥有保护者模式的唯一原因。它不像构造函数链接那样工作。 - Sanjay T. Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接