为什么java.lang.Object中的finalize()方法“受保护”?

时间:2010-02-18 19:14:01

标签: java finalize

出于好奇,

为什么finalize()方法的访问修饰符设为protected。为何不能public?有人可以解释我背后的具体原因吗?

另外,我发现finalize()方法只被调用一次。如果我在程序内部调用它两次,会发生什么?垃圾收集器会再次调用它吗?

private void dummyCall() {
    try {
        finalize();
        finalize();
    } catch (Throwable e) {
        e.printStackTrace();//NOT REACHES EXCEPTION
    }
}

9 个答案:

答案 0 :(得分:24)

我用另一个问题回答你的问题:

  

为什么finalize方法不受保护?

一般情况下,您应尽量保持私密性。这就是封装的全部内容。否则,您可以所有内容 publicfinalize不能是private(因为派生类应该能够访问它以便能够覆盖它),所以它至少应该是protected但是为什么在提供更多访问权限时这不可取吗?


在仔细阅读你的评论之后,我想我现在看到了你的要点。我认为你的观点是,因为所有内容都来自java.lang.Object并因此访问其protected成员,所以它(或java.lang.Object中的任何方法)不会有任何区别public而不是protected。就个人而言,我认为这是Java中的一个设计缺陷。这确实在C#中得到了修复。问题不在于finalize受到保护的原因。没关系。真正的问题是您不能通过基类类型的对象引用来调用基类中的受保护方法。 Eric Lippert有blog entry讨论为什么允许这种对受保护成员的访问是个坏主意further elaborated on Stack Overflow in this question

答案 1 :(得分:23)

  

为什么是finalize()方法的访问权限   修饰符被视为受保护。为什么   不能公开吗?

它不公开,因为它不应该被JVM以外的任何人调用。但是,它必须受到保护,以便可以由需要为其定义行为的子类覆盖它。

  

如果我在我的程序中调用它两次,   内部发生了什么?

你可以随心所欲地调用它,毕竟它只是一种方法。但是,与public static void main(String [] args)非常相似,它对JVM具有特殊含义

  

垃圾收集器会调用它吗?   再次?

答案 2 :(得分:12)

  • finalize意味着仅由gc调用,因此不需要公开访问
  • finalize保证只有一次被gc 调用,自己调用它会破坏这个保证,因为gc不会知道它。
  • 任何重写的课程都可以公开,我认为由于上述原因这是不好的
  • finalize不应包含太多代码,因为finalize抛出的任何异常都可能会终止gc的终结器线程。

反对最终确定()

  • 管理本机资源或任何需要调用dispose()或close()的资源可能导致很难找到错误,因为它们只会在jvm内存不足时释放,您应该手动释放资源。 Finalize只应用于调试资源泄漏或手动管理资源过多的情况。
  • finalize将在gc的另一个线程中调用,并可能导致资源锁定等问题。
  • 像WeakReference和ReferenceQueue这样的引用类是处理清理的另一种(相当复杂的)方法,可能与本机资源的finalize()有相同的问题。

请注意上述陈述中的错误,我有点累了: - )

答案 3 :(得分:3)

查看讨论它的this link

基本上,它最有意义的是private,因为它只应由JVM(垃圾收集器)调用。但是为了允许子类将父finalize()方法作为其finalize()的一部分调用,它必须是protected

编辑 - 只是一般警告 - 通常不鼓励使用finalize()方法,因为没有办法确保它会被调用。虽然这并不意味着你永远不会有机会使用它 - 这种情况很少见。)

答案 4 :(得分:3)

关于finalize()被调用的部分仅适用于来自GC的调用。您可以将对象想象为具有隐藏标志“finalize()由GC调用”,并且GC检查该标志以了解如何处理该对象。您可以通过自己的finalize()手动调用以任何方式影响该标志。

在最终确定后,请阅读Hans Boehm(他因垃圾收集工作而闻名)的this article。这是关于最终确定的大开眼界;特别是,Boehm解释了为什么最终确定必然是异步的。一个必然结果是,虽然最终确定是一个强大的工具,但它很少是给定工作的正确工具。

答案 5 :(得分:2)

它不是public(或默认访问权限),因为它意味着当对象被垃圾收集时由内部JVM调用 - 它的意味着被其他任何东西调用。而且它不是private,因为它意味着被覆盖,你不能覆盖私有方法。

  

如果我在我的程序中调用它两次,   内部发生了什么?请问   垃圾收集器会调用它   再次?

可能是的,但是很难想象这会产生任何意义的情况 - finalize()的一点是在对象被垃圾收集时进行清理。它甚至没有那么好,所以你应该完全避免而不是试验。

答案 6 :(得分:1)

finalize()仅供JVM用于在收集对象时清理资源。一个类定义应该对集合采取什么操作是合理的,它可能需要访问super.finalize()。调用finalize()对外部进程没有意义,因为外部进程无法控制何时收集对象。

答案 7 :(得分:1)

  

另外,我知道finalize()   方法只调用一次。如果我打电话   在我的程序中,它在内部两次   发生了什么事?

你可能会在C ++ ~destructors的印象中问这个问题。在java中,finalize()方法没有做任何魔术(比如清除内存)。它应该被垃圾收集器调用。但反之亦然。

我建议你阅读Joshua Bloch的“Effective Java”中的通讯章节。它说使用终结器是一种不好的做法,可能会导致性能和其他问题,并且只有几种情况应该使用它们。本章以下一个词开头:

  

终结者通常是不可预测的   危险的,而且通常是不必要的。

答案 8 :(得分:1)

我认为finalize受保护的原因可能是它被JDK中的某些类覆盖,而这些被覆盖的方法由JVM调用。