繁体   English   中英

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

[英]Why is the finalize() method in java.lang.Object “protected”?

出于好奇,

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

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

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

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

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

通常,您应该尝试使事物尽可能私密。 这就是封装的全部内容。 否则,您可以将所有内容 public finalize不能是private (因为派生类应该能够访问它才能覆盖它),因此它至少应该protected但是为什么在不希望使用时赋予更多访问权限呢?


在更仔细地阅读了您的评论之后,我想我现在明白了您的要点。 我认为您的意思是,由于所有内容都源自java.lang.Object并因此访问其protected成员,因此将其public (或与此相关的java.lang.Object任何方法)没有任何区别protected 我个人认为这是Java的设计缺陷。 这确实在C#中已修复。 问题不是为什么finalize受保护。 没关系。 真正的问题是,您不应该能够通过基类类型的对象引用来在基类中调用受保护的方法。 埃里克·利珀特(Eric Lippert)的博客条目讨论了为什么允许这种方式访问​​受保护成员不是一个好主意, 对此问题在“堆栈溢出”中作了进一步阐述

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

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

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

您可以随意调用它,毕竟它只是一个方法。 但是,就像public static void main(String [] args) ,它对JVM有特殊的意义。

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

  • finalize只能由gc调用,因此不需要公共访问
  • finalize保证仅由gc调用一次,您自己调用它会破坏此保证,因为gc对此一无所知。
  • 任何压倒一切的课程都可以将最终定稿公开,由于上述原因,我认为这是不好的
  • finalize不应包含太多代码,因为finalize引发的任何异常都可能杀死gc的finalizer线程。

反对finalize()

  • 管理本机资源或需要调用dispose()或close()的任何资源可能会导致难以发现错误,因为这些错误仅在jvm内存不足时才被释放,您应该手动释放资源。 Finalize仅应用于调试资源泄漏或用于手动管理资源的工作过多的情况。
  • finalize将在gc的附加线程中调用,并可能导致资源锁定等问题。
  • 像WeakReference和ReferenceQueue这样的引用类是处理清除的另一种方法(相当复杂),并且可能与本机资源的finalize()一样。

当心上面声明中的错误,我有点累:-)

查看讨论该链接

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

编辑 -只是一般性的警告-由于没有办法确保调用它,因此通常不建议使用finalize()方法。尽管这并不意味着您永远不会有使用它的方法-很少见。)

关于finalize()仅被调用一次的部分仅适用于来自GC的调用。 您可以想象该对象具有隐藏标志“ GC调用了finalize() ”,然后GC检查该标志以了解如何处理该对象。 您自己手工调用finalize()不会对标志产生任何影响。

完成后,请阅读Hans Boehm(以垃圾收集工作而闻名的文章 )。 这对完成工作大开眼界。 Boehm特别说明了为什么终止必须是异步的。 一个必然的结论是,虽然最终确定是一个强大的工具,但对于给定的工作而言,它很少是正确的工具。

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

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

可能是的,但是很难想象会有什么意义的情况finalize()的目的是在垃圾回收对象时进行清理。 而且它甚至还不能很好地完成工作,因此,您确实应该完全避免而不是进行试验。

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

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

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

您可能会在C ++〜析构函数的印象下问这个问题。 在Java中,finalize()方法没有任何作用(例如清除内存)。 应该由垃圾收集器调用。 但反之亦然。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM