为什么java.lang.Object中的finalize()方法是“protected”?

出于好奇,

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

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

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

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

为什么finalize方法不应受到保护?

总的来说,你应该尽可能保持私密性。 这就是封装的全部内容。 否则,你可以把一切都 publicfinalize不能是private (因为派生类应该可以访问它来覆盖它),所以它至less应该protected但为什么在不希望的时候给出更多的访问呢?


在仔细阅读你的评论之后,我想我现在看到你的主要观点。 我认为你的观点是因为一切从java.lang.Object派生,因此访问它的protected成员,它不会有任何区别(或任何方法在这个问题的java.lang.Object )是public ,而不是protected 。 就我个人而言,我认为这是Java的一个devise缺陷。 这确实在C#中修复。 问题不在于为什么finalize是受保护的。 没关系。 真正的问题是你不能通过基类types的对象引用来调用基类中的受保护的方法。 Eric Lippert有一篇博客文章,讨论为什么允许对受保护成员进行这种访问是一个糟糕的主意, 这个问题在Stack Overflow上有进一步的阐述 。

为什么finalize()方法的访问修饰符被设置为受保护的。 为什么不能公开?

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

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

你可以把它叫做你想要的,毕竟它只是一个方法。 然而,就像public static void main(String [] args) ,它对JVM有特殊的意义

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

  • 最终确定只能由gc调用,因此不需要公共访问
  • 最终确保只能被gc调用一次,自己调用它会打破这个保证,因为gc不会知道它。
  • 任何压倒一切的阶级都可以最终公开,我认为这是不利于上述原因的
  • finalize不应该包含太多的代码,因为finalize引发的任何exception都可能会终止gc的终结器线程。

反对敲定()

  • pipe理本地资源或任何需要调用dispose()或close()的资源可能会导致很难发现错误,因为只有当jvm内存不足时才会释放错误,您应该手动释放资源。 Finalize只能用于debugging资源泄漏或手动pipe理资源过多的情况。
  • finalize将会在gc的一个额外的线程中被调用,并可能导致资源locking等问题。
  • 像WeakReference和ReferenceQueue这样的引用类是处理清理的替代(相当复杂的)方法,并且可能与本地资源的finalize()具有相同的问题。

谨防上述说法中的错误,我有点厌倦:-)

看看这个讨论它的链接 。

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

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

关于finalize()被调用一次的部分只适用于来自GC的调用。 你可以想象这个对象有一个隐藏的标志“ finalize()被GC调用”,并且GC检查该标志以知道如何处理该对象。 这个标志不会被你自己的手工调用finalize()

完成后,请阅读Hans Boehm 撰写的这篇文章 (他以垃圾收集工作而着称)。 这是令人大开眼界的决定; 特别是Boehm解释了为什么最终化必然是asynchronous的。 一个必然的结论是,虽然最终确定是一个强大的工具,但对于一个给定的工作来说,这是非常less的工具。

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

如果我在程序中调用两次,内部发生了什么? 垃圾收集器会再次调用这个吗?

很可能是的,但是很难想象这种情况会有什么意义 – finalize()在于当垃圾收集对象时进行清理。 而且它甚至不能很好地完成,所以这是你应该完全避免而不是试验的东西。

finalize()仅在收集对象时由JVM使用来清理资源。 对于一个类来说,定义在采集上应该采取什么行动是合理的,为此可能需要访问super.finalize()。 外部进程调用finalize()是没有意义的,因为外部进程不能控制何时收集对象。

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

你可能会问这个C ++〜析构函数的印象。 在java中,finalize()方法不会有任何魔法(如清除内存)。 它应该被垃圾收集器调用。 但是,反之亦然。

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

终结者是不可预知的,往往是危险的,通常是不必要的。

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

Interesting Posts