《Effective Java 中文版 第二版》

《Effective Java 中文版 第二版》第二章 第7条:

2017-12-02  本文已影响0人  不平凡的小黄宁

本章的主题是创建和销毁对象:何时以及如何创建对象,何时以及如何避免创建对象,如何确保它们能够适时地销毁,以及如何管理对象销毁之前必须进行的各种清理动作。


[toc]

终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。使用终结方法会导致行为不稳定、降低性能,以及可移植性问题。当然,终结方法也有其可用之处。

当一个对象变得不可到达的时候,垃圾回收器会回收与该对象相关联的存储空间,并不需要程序员做专门的工作。

终结方法缺点

1. 不能保证会被及时地执行。

2. 如果异常发生在终结方法之中,则不会使线程终止,并打印出栈轨迹(Stack Trace),甚至连警告都不会打印出来。

3. 非常严重的(Severe)性能损失。

解决方法

提供一个显式的终止方法,并要求该类的客户端在每个实例不再有用的时候调用这个方法。

// try-finally block guarantees execution of termination method
    Foo foo = new Foo(...);
    try {
        // Do what must be done with foo
         ...
    } finally {
        foo.terminate(); // Explicit termination method
    }

终结方法合法用途

充当“安全网(safety net)”

与对象的本地对等体(native peer)有关

最终方法链

值得注意的一点是,“最终方法链(finalizer chaining)”并不会自动执行。如果类(不是Object)有终结方法,并且子类覆盖了终结方法,子类的终结方法就必须手动调用超类的终结方法。你应该在一个try块中终结子类,并在相应的finally块中调用超类的终结方法。
这样做可以保证:即使子类的终结过程抛出异常,超类的终结方法也会得到执行。反之亦然。

终结方法守卫者(finalizer guardian)

如果子类实现者覆盖了超类的最终方法,但是忘了手动调用超类的最终方法(或者有意选择不调用),那么超类的最终方法永远也不会被调用到。

// Finalizer Guardian idiom
public class Foo {
    // Sole purpose of this object is to finalize outer Foo object
    private final Object finalizerGuardian = new Object() {
        @Override protected void finalize() throws Throwable {
        ... // Finalize outer Foo object 终结外部实例 Foo
        }
    };
    ... // Remainder omitted
}

注意,公有类Foo并没有终结方法(除了Object中继承了一个无关紧要之外),所以子类的最终方法是否调用super.finalize并不重要。对于每一个带有最终方法的非final公有类,都应该考虑使用这种方法。

总结

总之,除非是作为安全网,或者是为了终止非关键的本地资源、否则请不要使用终结方法。在这些很少见的情况下,既然使用了终结方法,就要记住调用super.finalize。如果用终结方法作为安全网,要记得记录终结方法的非法用法。最后,如果需要把终结方法与公有的非final类关联起来,请考虑使用终结方法守卫者,以确保即使子类的终结方法未能调用super.finalize,该终结方法也会被执行。

上一篇 下一篇

猜你喜欢

热点阅读