为什么Netbeans会警告我使用finalize方法?

3

我在Java7中实现了一个类。它没有继承/实现任何东西。它使用Tess4J,所以我认为在最后释放资源会很好。因此,我重写了finalize()方法,就像这样:

@Override
protected void finalize() throws Throwable 
{
    try
    {
        TessAPI1.TessBaseAPIDelete(handle);
    }
    catch(Throwable t)
    {
        throw t;
    }
    finally
    {
        super.finalize();
    }
}

Netbeans 8.0.2给我关于这个方法的警告:

finalize declared()

Netbeans网站上的描述对我来说并没有更多的帮助:
warns about implementation of Object.finalize()

我并没有覆盖其他方法,比如 equals 方法等(也许我应该这样做?)。 你能告诉我为什么会出现这个警告吗?


1
相关阅读:http://weblog.ikvm.net/2003/11/09/FinalizeConsideredHarmful.aspx - Erich Kitzmueller
《Effective Java》中的引述:“Finalizers是不可预测的,常常危险,而且通常是不必要的”。 - assylias
2
捕获并立即重新抛出异常是毫无意义的。这样的catch块可以被移除,因为它没有真正的影响。 - Natix
@Natix 谢谢!我不知道我可以省略 catch 部分。 - nuoritoveri
3个回答

4
finalize 方法的问题在于它们可能会被任意线程在任意时间调用,甚至可能根本不被调用。就像在这个问题中讨论的一样,它们可能会在实例方法仍在执行时被意外调用,因此使用它们来释放资源非常危险。
因此,如果它们并没有真正发挥原始目的,那么在使用它们时总是警告是合理的。
如果您想实现清理资源的代码,当客户端代码忘记调用closedispose或其他提供显式资源管理的方法时(如果有相关的本地资源,则应该提供),可以使用PhantomReference到实例和一个ReferenceQueue
优点在于您可以控制何时轮询队列并执行清理操作,甚至可以通过让PhantomReference超出范围(它将被普通收集而不是进入队列)来选择退出事后清理,前提是客户端代码没有忘记调用close(强烈建议实现AutoClosable以允许使用try with resources”)。因此,这也解决了对象具有非平凡的finalize方法必须收集两次的小性能问题,因为执行finalize方法意味着它们变得可达。

2
一般来说,大多数Java程序员没有理由实现finalize(),因为他们自己的代码只使用已经受管理的类(因此这些类已经有了自己的finalizers)。 (请参见问题下面的评论。)
一些开发人员可能不知道垃圾收集器的真正工作原理,因此依赖于finalize()来执行应该在其他地方完成的清理工作。 这种错误尤其容易导致测试中忽略的缺陷,在生产中则会导致故障。
出于这个原因,我认为警告finalize()是适当的。

0

当 JVM 进行垃圾回收时,将调用 finalize()。因此,资源可能无法按您的意愿释放。

请改用 try finally。


处理在对象生命周期中被多次调用,且有不同类型。我能否将每个处理方法的代码用try-finally包围起来(这样做是否是一个好习惯)? - nuoritoveri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接