【问题标题】:Why Netbeans warns me of finalize?为什么 Netbeans 警告我完成?
【发布时间】:2015-01-31 23:02:51
【问题描述】:

我在 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 或任何其他方法(也许我应该这样做?)。 你能告诉我为什么会收到这个警告吗?

【问题讨论】:

  • 来自 Effective Java 的引述:“终结器是不可预测的,通常是危险的,而且通常是不必要的”。
  • 捕获并立即重新抛出异常是没有意义的。这样的 catch 块可以删除,因为它没有实际效果。
  • @Natix 谢谢!我不知道我可以省略catch 部分。

标签: java netbeans java-7 finalize


【解决方案1】:

一般来说,大多数 Java 程序员从来没有理由实现finalize(),因为他们自己的代码只使用已经托管的类(因此有自己的终结器)。 (见问题下方的 cmets)。

一些开发人员可能不知道垃圾收集器的实际工作原理,因此依赖finalize() 来完成应该在其他地方完成的清理工作。这个错误尤其会导致在测试中未被注意到但在生产中导致失败的缺陷。

出于这个原因,我认为关于finalize() 的警告是合适的。

【讨论】:

    【解决方案2】:

    finalize 方法的问题是它们可能在任意时间被任意线程调用,甚至根本不调用。和discussed in this question 一样,它们可能会被提前调用,即当实例方法仍在执行时,因此使用它们来释放资源是非常危险的。

    因此,如果它们对最初的用途没有真正的用处,那么在使用它们时始终发出警告是合理的。


    如果您想实现清理资源的代码,当客户端代码忘记调用 closedispose 或您为显式资源管理提供的任何内容时(如果有关联的本机资源,您应该这样做)可以对实例使用PhantomReferenceReferenceQueue 完成。

    优点是您可以控制何时轮询队列并执行清理,您甚至可以通过让 PhantomReference 超出范围来选择退出事后清理(通常会被收集而不是enqueued)在客户端代码没有忘记调用close的情况下(强烈建议实现AutoClosable以允许使用try with resources”)。所以这也解决了一个小的性能问题,即具有非平凡finalize 方法的对象必须被收集两次,因为执行finalize 方法意味着它们再次变得可访问。

    【讨论】:

      【解决方案3】:

      finalize() 在 jvm 去 gc 时被调用。所以可能资源没有如你所愿释放。

      使用 try finally 代替。

      【讨论】:

      • 对象生命周期内多次调用处理,有不同的类型。我可以用 try-finally 包围每个处理方法代码吗(这是一个好习惯)吗?