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

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

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

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


当前回答

当编写将被其他开发人员使用的代码时,需要调用某种“清理”方法来释放资源。有时那些其他开发人员忘记调用您的清理(或关闭,或销毁,或其他)方法。为了避免可能的资源泄漏,您可以检查finalize方法,以确保该方法被调用,如果没有调用,您可以自己调用它。

许多数据库驱动程序在它们的Statement和Connection实现中这样做,以提供一点安全性,防止开发人员忘记调用close。

其他回答

作为旁注:

覆盖finalize()的对象由垃圾回收器进行特殊处理。通常,在对象不再在作用域中后,在收集周期中立即销毁对象。但是,可终结对象被移到队列中,在队列中,独立的终结线程将耗尽队列并在每个对象上运行finalize()方法。一旦finalize()方法终止,对象就可以在下一个循环中进行垃圾收集了。

源代码:finalize()在java-9上已弃用

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

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

我不知道你是怎么想的,但是…

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

所以我猜《太阳报》找到了一些(他们认为)应该使用它的案例。

自1998年以来,我一直在从事Java专业工作,但我从未实现过finalize()。一次也没有。

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

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

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

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

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

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

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

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

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