Answers:
根据约书亚·布洛赫(Joshua Bloch)的《有效Java(第二版)》,有两种情况下finalize()
有用:
一种方法是充当“安全网”,以防对象所有者忘记调用其显式终止方法。虽然不能保证将立即调用终结器,但在客户端无法调用显式终止方法的那些(希望如此)的情况下(最好是极少数),释放资源比延迟释放更好。但是,如果终结器发现资源尚未终止,则终结器应记录一条警告
终结器的第二个合法用途是与本机对等对象有关。本机对等体是普通对象通过本机方法委托给的本机对象。由于本机对等体不是普通对象,因此垃圾回收器不了解它,并且在回收其Java对等体时也无法对其进行回收。终结器是执行此任务的合适工具,假定本地对等方不持有任何关键资源。如果本机对等方拥有必须立即终止的资源,则该类应具有显式终止方法,如上所述。终止方法应执行释放关键资源所需的任何操作。
要进一步阅读,请参阅第27页的项目7。
终结器对于本地资源的管理很重要。例如,您的对象可能需要使用非Java API从操作系统分配WidgetHandle。如果在对对象进行GC处理时不释放该WidgetHandle,则将泄漏WidgetHandles。
重要的是,“永远不会调用finalizer”案例很简单:
在这三种情况下,您要么没有本机泄漏(由于程序不再运行),要么就已经有非本机泄漏(如果继续分配托管对象而不使用它们) GC')。
“不要依赖终结器被调用”警告实际上是关于不将终结器用于程序逻辑。例如,您不想跟踪在程序的所有实例中存在多少个对象,方法是在构造过程中在某个位置增加文件中的计数器,然后在终结器中减少它的数量,因为无法保证对象会最终,该文件计数器可能永远不会返回到0。这实际上是更一般原则的一种特殊情况,您不应依赖于程序正常终止(电源故障等)。
但是,对于本机资源的管理,终结器不运行的情况对应于您不关心终结器是否不运行的情况。
close()
在无法到达之前从未调用过),可能是更正确的选择
API文档中解释了此方法的用途,如下所示:
当Java虚拟机确定不再有任何方法可以由尚未死亡的任何线程访问此对象时,将调用该方法,除非是由于某些其他对象的完成而采取的措施或即将结业的课程...
...的通常目的
finalize
是在不可丢弃的对象被丢弃前执行清理动作。例如,代表输入/输出连接的对象的finalize方法可能会执行显式I / O事务,以在永久丢弃该对象之前断开连接...
如果您还对语言设计者为什么选择“对象不可撤消地丢弃”(垃圾回收)超出应用程序程序员无法控制的方式(“我们永远不要依赖”)的原因感兴趣,请参见对问题:
自动垃圾收集...消除了困扰C和C ++程序员的整个编程错误类别。您可以放心地开发Java代码,以确保系统会迅速发现许多错误,并且直到生产代码交付后,重大问题才会处于休眠状态。
上面的引言来自于有关Java设计目标的官方文档,也就是说,可以将其视为解释Java语言设计者为何如此决定的权威参考。
有关此首选项的更详细且与语言无关的讨论,请参阅OOSC的9.6节自动内存管理(实际上,如果您对这样的东西感兴趣,不仅此部分,而且整个第9章也非常值得阅读)。本节以明确的声明开头:
好的OO环境应该提供一种自动内存管理机制,该机制将检测并回收无法访问的对象,从而使应用程序开发人员可以专注于自己的工作-应用程序开发。
前面的讨论应该足以表明拥有这样一种设施的重要性。用Michael Schweitzer和Lambert Strether的话说:
没有自动内存管理的面向对象程序与没有安全阀的压力锅大致相同:迟早肯定会崩溃!
卡瓦特:我可能已经过时了,但这是我几年前的理解:
通常,无法保证终结器何时运行-甚至根本无法运行,尽管某些JVM可以让您在程序退出之前请求完整的GC和终结处理(这当然意味着程序需要更长的时间)退出,这不是默认的操作模式)。
众所周知,某些GC会明确延迟或避免使用带有终结器的GC'ing对象,以期在基准测试上产生更好的性能。
不幸的是,这些行为与建议使用终结器的最初原因相抵触,并鼓励使用显式调用的关闭方法。
如果您有一个在丢弃之前确实必须清理的对象,并且如果您真的不信任用户这样做,那么终结器可能仍然值得考虑。但是总的来说,有充分的理由使您在现代Java代码中不像在某些早期示例中那样频繁地看到它们。
《Google Java风格指南》对此主题提出了一些明智的建议:
覆盖是非常罕见的
Object.finalize
。提示:不要这样做。如果绝对必须,请非常仔细地阅读并理解有效的Java项目7,“避免使用终结器”,然后再不这样做。
PhantomReference
和来构建它ReferenceQueue
。
PhantomReference
也是更好的解决方案。终结器是Java早期遗留下来的疣,而喜欢Object.clone()
和原始类型则是人们最容易忘记的语言的一部分。
终结器提供了释放资源的机会,这些资源无法由自动存储管理器自动释放。在这种情况下,简单地回收对象使用的内存并不能保证将回收其持有的资源。