你为什么要实现finize()?

2022-08-31 04:41:21

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

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

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

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


答案 1

您可以将其用作包含外部资源(套接字、文件等)的对象的后备站。实现需要调用的方法和文档。close()

实现以在检测到尚未完成处理时执行处理。也许有一些东西被抛弃,以指出你正在清理一个有缺陷的来电者。finalize()close()stderr

它在特殊/越野车情况下提供额外的安全性。并非每个呼叫者每次都会做正确的事情。不幸的是,但在大多数环境中都是如此。try {} finally {}

我同意它很少需要。正如评论者指出的那样,它带有GC开销。仅当您在长时间运行的应用程序中需要“皮带和吊带”安全性时才使用。

我看到从Java 9开始,Object.finalize()被弃用了!他们向我们指出java.lang.ref.Cleanerjava.lang.ref.PhantomReference作为替代方案。


答案 2

finalize()是对 JVM 的提示,即在未指定的时间执行代码可能会很好。当您希望代码神秘地无法运行时,这很好。

在终结器中执行任何重要操作(基本上除了日志记录之外的任何内容)在三种情况下也是好的:

  • 你想赌其他最终确定的对象仍将处于程序的其余部分认为有效的状态。
  • 您希望向具有终结器的所有类的所有方法中添加大量检查代码,以确保它们在最终确定后行为正确。
  • 你想意外地复活最终确定的对象,并花很多时间试图弄清楚为什么它们不起作用,和/或为什么它们在最终发布时没有最终完成。

如果你认为你需要finize(),有时你真正想要的是一个幻像引用(在给出的示例中,它可以保存对其引用使用的连接的硬引用,并在幻像引用排队后关闭它)。这也具有它可能神秘地永远不会运行的属性,但至少它不能调用方法或复活最终确定的对象。因此,它非常适合您不需要完全关闭该连接的情况,但是您非常希望这样做,并且您类的客户端不能或不会自己调用 close(这实际上足够公平 - 如果您设计的接口需要在收集之前采取特定操作,那么拥有垃圾回收器有什么意义?这只会让我们回到malloc/free的时代。

其他时候,您需要您认为自己管理的资源来使其更加强大。例如,为什么需要关闭该连接?它最终必须基于系统提供的某种I / O(套接字,文件等),那么当最低级别的资源被gced时,为什么不能依靠系统来关闭它呢?如果另一端的服务器绝对要求您干净地关闭连接,而不仅仅是丢弃套接字,那么当有人通过运行代码的机器的电源线绊倒或中间网络熄灭时会发生什么?

免责声明:我过去曾参与过 JVM 实现。我讨厌终结器。


推荐