读书笔记 仅供参考
Java 的终结方法和 C++ 的析构函数不是相同的事物,C++ 的析构函数可以用来回收对象所占用的资源,而 Java 有垃圾回收器自动回收。如果确实有关闭资源的需要,使用 try-finally 或 try-with-resource( Java 1.7)。
缺点一
由于 Java 的资源确定是否回收是有可达性确定(详见 Java 虚拟机),但是从一个对象不可达到终结方法执行,中间的时间是任意长的,所以不能再终极方法中关闭资源或其他注重时间的任务,否则会导致各种错误。
缺点二
如果使用了终结方法,然后在终结方法中的程序可能会抛出没有捕获的异常,按摩这种异常是不会被观测到的,警告也不会出现。而在这种情况,对象的终结过程也停止了,对象处于破坏的状态,假如此时有另一个线程企图使用这个对象,那么会发生任何不确定的行为。
缺点三
非常严重的性能损失,在作者的例子中有430倍的差距。
解决方法
如果类中的资源确实是要终止,那么好的做法是提供一个显示的终止方法,并且要求再每个实例不再有用的时候调用这个方法。
一个细节:该实例必须记录下自己是否已经被终止了。
例子:InputStream 的 close() 方法。
终结方法合法用途一:安全网
当对象的使用者忘记调用显示的终结方法,终结方法可以充当安全网。迟一点释放资源总比不释放资源号。
ps:如果终结方法中发现资源没有被种子,应该在日志中记录。
终结方法合法用途二:本地对象体
本地对象体是一个本地对象,与本地方法有关。垃圾回收器不知道有本地对象的存在,所以不会被回收。在本地对象体不拥有关键资源的前提下,终结方法是终结这个本地对象体最好的工具,否则还是需要显示的终结方法。
终结方法链
终结方法链不会自动的执行,即:一个类(非 Object)有终结方法,它的子类覆盖了终结方法,那么应该显示的调用父类的终结方法(super.finalize()),最好在 finally 块中执行。如果不显示的调用,父类的终结方法永远不会被调用。
要防止上面的问题,需要为每个对象创建一个附加的对象。把终结方法放在一个匿名类中,这个匿名类的唯一作用就是终结它的外围类。匿名类的实例称为终结方法守卫者。当守卫者被终结的时候,它会执行外围实例的终结方法。