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

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

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

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


当前回答

Finalize()对于捕获资源泄漏非常有用。如果资源应该关闭,但没有关闭,则将资源未关闭的事实写入日志文件并关闭。通过这种方式,您可以删除资源泄漏,并提供一种方法来知道它已经发生,以便您可以修复它。

我从1.0 alpha 3(1995)开始就一直在用Java编程,我还没有覆盖任何东西的finalize…

其他回答

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

编辑:好吧,这真的不管用。我实现了它,并认为如果它有时失败了,这对我来说是可以的,但它甚至没有调用finalize方法一次。

我不是一个专业的程序员,但在我的程序中,我有一个案例,我认为是一个使用finalize()的好例子,那是一个缓存,在它被销毁之前将其内容写入磁盘。因为它没有必要在每次销毁时都执行,它只会加速我的程序,我希望我没有做错。

@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}

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

    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);
        }
    }

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

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

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

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

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