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

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

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

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


当前回答

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

其他回答

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

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

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

您不应该依赖finalize()来为您清理资源。Finalize()在类被垃圾回收之前不会运行。在使用完资源后显式地释放资源要好得多。

您可以将它用作持有外部资源(套接字、文件等)的对象的支持。实现close()方法和需要调用它的文档。

如果检测到close()没有执行,则实现finalize()来执行close()处理。可能会将一些东西转储到stderr,以指出您正在清理有错误的调用者。

它在异常/有bug的情况下提供了额外的安全性。并不是每个调用者每次都会执行正确的try {} finally{}。不幸的是,但在大多数环境中都是如此。

我同意很少有人需要它。正如评论者指出的那样,它带来了GC开销。只有当你在一个长期运行的应用程序中需要“皮带和背带裤”的安全性时才使用。

我看到从Java 9开始,Object.finalize()已弃用!它们将我们指向java.lang.ref.Cleaner和java.lang.ref.PhantomReference作为替代。

iirc——你可以使用finalize方法作为实现昂贵资源池机制的一种手段——这样它们就不会得到GC了。

删除已经添加到全局/静态位置(不需要)的东西,并在对象被删除时需要删除,这是很方便的。例如:

    private void addGlobalClickListener() {
        weakAwtEventListener = new WeakAWTEventListener(this);

        Toolkit.getDefaultToolkit().addAWTEventListener(weakAwtEventListener, AWTEvent.MOUSE_EVENT_MASK);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();

        if(weakAwtEventListener != null) {
            Toolkit.getDefaultToolkit().removeAWTEventListener(weakAwtEventListener);
        }
    }