我一直在阅读很多关于finalize()的Java新手问题,并发现没有人真正清楚地表明finalize()是一种不可靠的清理资源的方法,这有点令人困惑。我看到有人评论说他们用它来清理连接,这真的很可怕,因为唯一接近于保证连接关闭的方法是最后实现try (catch)。

我没有学过CS,但我已经用Java专业编程近十年了,我从来没有见过有人在生产系统中实现finalize()。这并不意味着它没有用处,或者和我一起工作的人一直在做正确的事情。

所以我的问题是,实现finalize()有哪些用例不能通过语言中的另一个进程或语法更可靠地处理?

请提供具体的场景或您的经验,简单地重复Java教科书,或最终确定的预期用途是不够的,因为这不是这个问题的意图。


当前回答

嗯,我曾经用它来清理没有返回到现有池的对象。

它们经常被转来转去,所以不可能知道什么时候能安全地放回泳池。问题在于,它在垃圾收集过程中带来了巨大的损失,远远超过了使用对象池节省的成本。在我拆除整个池,让所有内容都变得动态并完成之前,它已经投入了大约一个月的时间。

其他回答

为了强调以上答案中的一点:终结器将在单独的GC线程上执行。我听说过一个大型的Sun演示,开发人员在一些终结器中添加了一个小睡眠,并故意让一个原本花哨的3D演示崩溃。

最好避免,可能的例外是test-env诊断。

Eckel的《Thinking in Java》在这方面有一个很好的章节。

接受的答案列出了在finalize期间关闭资源的操作。

然而,这个答案表明,至少在使用JIT编译器的java8中,您会遇到意想不到的问题,有时甚至在您完成从对象维护的流中读取之前就调用了终结器。

所以即使在这种情况下,也不建议调用finalize。

嗯,我曾经用它来清理没有返回到现有池的对象。

它们经常被转来转去,所以不可能知道什么时候能安全地放回泳池。问题在于,它在垃圾收集过程中带来了巨大的损失,远远超过了使用对象池节省的成本。在我拆除整个池,让所有内容都变得动态并完成之前,它已经投入了大约一个月的时间。

我在生产代码中使用finalize的唯一一次是执行一个检查,检查给定对象的资源是否已被清理,如果没有,则记录一个非常明显的消息。它实际上并没有尝试自己去做,如果做得不好,它就会大喊大叫。结果很有用。

公认的答案是好的,我只是想补充的是,现在有一种方法来实现finalize的功能,而不实际使用它。

看看“Reference”类。弱引用,幻影引用和软引用。

您可以使用它们来保存对所有对象的引用,但是这个引用ALONE不会停止GC。这样做的好处是,当它被删除时,你可以让它调用一个方法,并且这个方法可以保证被调用。

至于finalize: 我使用finalize一次来了解哪些对象正在被释放。你可以用静态、引用计数等来玩一些巧妙的游戏——但这只是为了分析,但要注意这样的代码(不只是在finalize中,但这是你最有可能看到它的地方):

public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}

这表明某人不知道自己在做什么。像这样的“清理”实际上是不需要的。当类被GC化时,这将自动完成。

如果你在finalize中发现这样的代码,那肯定是编写它的人搞糊涂了。

如果它在其他地方,可能是代码是一个坏模型的有效补丁(一个类存在很长一段时间,由于某种原因,它引用的东西必须在对象GC之前手动释放)。一般来说,这是因为有人忘记删除监听器或其他东西,不知道为什么他们的对象没有被GC,所以他们只是删除它引用的东西,耸耸肩然后离开。

它永远不应该被用来“更快”地清理东西。