(此问题不同于您为什么要实现finalize()?此问题与从Java平台弃用有关,另一个问题与在应用程序中是否应使用此机制有关。)
为什么finalize()
在Java 9中不推荐使用该方法?
是的,它可能以错误的方式使用(例如,从垃圾收集中保存对象(虽然仅一次)或尝试关闭其中的某些本机资源(总比不完全关闭要好))以及许多其他方法可能会被错误地使用。
那么,是finalize()
真的如此危险或绝对没有用,有必要将其逐出Java吗?
尽管问题是关于Object.finalize
方法的问题,但主题实际上是关于 最终确定 机制的整体。该机制不仅包括表面API
Object.finalize
,还包括有关对象生命周期的编程语言规范,以及对JVM中垃圾回收器实现的实际影响。
从应用程序的角度,已经写了很多关于为什么难以使用终结处理的文章。看到问题,为什么要实施finalize()?并且Java 9Cleaner是否应优先于定稿?和他们的答案。另请参阅 有效的Java,第3版, 由Joshua
Bloch,项目8。
简要地说,有关使用终结器的问题的几点是:
众所周知,它们很难正确编程
特别是当对象意外无法到达(但正确)时,它们可能会意外运行
最终确定可以轻松打破子类/超类关系
终结器之间没有顺序
给定对象的finalize
方法最多由JVM调用一次,即使该对象已“复活”
无法保证最终确定的及时性,甚至根本无法保证
没有明确的注册或注销机制
以上是使用finalization的困难。考虑到上述问题,正在考虑使用终结处理的任何人都应重新考虑。但是这些问题是否足以弃用Java平台中的终结处理?以下各节中说明了几个其他原因。
最终确定可能会使系统易碎
即使您编写的对象正确使用了终结处理,将对象集成到较大的系统中也会导致问题。即使您根本不使用终结处理,将其集成到较大的系统中(其中某些部分使用终结处理)也可能导致问题。通常的问题是,创建垃圾的工作线程需要与垃圾收集器保持平衡。如果垃圾收集器落后了,那么至少某些收集器可以“阻止世界”并进行完整的收集以赶上。终结使这种交互变得复杂。即使垃圾收集器跟上了应用程序线程的速度,结束处理也可能会导致瓶颈并降低系统速度,或者可能导致释放资源时出现延迟,从而导致这些资源的耗尽。这是一个
系统 问题。即使使用终止的实际代码正确无误,在正确编程的系统中仍然可能出现问题。
最终确定会导致安全问题
适用于Java 的 SEI CERT Oracle编码标准
具有一条规则MET12-J:不要使用终结器。(请注意,这是一个有关安全编码的网站。)特别是,它说
终结器使用不当会导致垃圾回收就绪对象的复活,并导致拒绝服务漏洞。
Oracle的 Java
SE安全编码指南对
使用终结处理可能引起的潜在安全性问题更为明确。在这种情况下,使用终结处理的代码不是问题。取而代之的是, 攻击者
可以使用终结处理来攻击尚未适当防御的敏感代码。特别是, 准则7-3 / OBJECT-3 规定,
可以通过终结器攻击来访问非最终类的部分初始化实例。攻击者
finalize
在子类中重写受保护的方法,并尝试创建该子类的新实例。这种尝试失败了……但是攻击者只是忽略了任何异常,而是等待虚拟机对部分初始化的对象执行最终化。发生这种情况时,将finalize
调用恶意方法实现,从而使攻击者可以访问this
,该引用指向最终确定的对象。尽管仅部分初始化了对象,但攻击者仍可以在其上调用方法…。
因此,平台中终结机制的存在给试图编写高保证代码的程序员带来了负担。
最终确定增加了规格的复杂性
Java平台由多种规范定义,包括语言,虚拟机和类库API的规范。最终确定的影响在所有这些方面都散布得很细,但它反复使它感到存在。例如,完成与对象创建之间的交互非常微妙(已经足够复杂了)。Finalization也已经出现了Java的公共API,这意味着(到目前为止)要求这些API进行演变以保持与先前指定的行为兼容。不断完善这些规范会使最终确定的成本更高。
最终确定给实施增加了复杂性
这主要是关于垃圾收集器的。有几种垃圾回收实现,并且都需要支付实现终结的成本。如果不使用终结处理,这些实现非常擅长将运行时开销降至最低。但是,实现仍然需要存在,并且需要正确且经过良好测试。这是持续的开发和维护负担。
摘要
We’ve seen elsewhere that it’s not recommended for programmers to use
finalization. However, if something is not useful, it doesn’t necessarily
follow that it should be deprecated. The points above illustrate the fact that
even if finalization isn’t used, the mere presence of the mechanism in the
platform imposes ongoing specification, development, and maintenance costs.
Given the lack of usefulness of the mechanism and the costs it imposes, it
makes sense to deprecate it. Eventually, getting rid of finalization will
benefit everyone.
截至撰写本文时(2019-06-04),尚无具体计划从Java中删除终结处理。但是,这样做当然是有意图的。我们已弃用该Object.finalize
方法,但尚未将其标记为删除。正式建议程序员停止使用此机制。非正式地知道不应该使用终结处理,但是当然有必要采取正式的步骤。此外,不赞成使用finalize
库类中的某些方法(例如ZipFile.finalize
)以“删除”,这意味着这些类的最终确定行为可以从将来的版本中删除。最终,我们希望在JVM中禁用终结处理(也许首先是可选的,然后是默认情况下的禁用),
问题内容: 众所周知,Java 中的接口已损坏。造成这种情况的原因很多,我将不再赘述。其他人已经做到了。这也是Java架构师本身的立场。 因此,我的问题是:为什么还不被弃用?如果核心Java团队已确定它已损坏,那么他们还必须考虑过时。他们反对这样做的原因是什么(在Java 8中仍不建议弃用)? 问题答案: 有一个错误在1997年提交给Java的错误数据库有关添加方法,所以将不再是无用的。它以“无法
问题内容: 我曾经在hibernate 3中使用getHibernateTemplate(),现在我转向了Hibernate 4,在这里我找不到以下类: 在这里我已经阅读过有关它的更多信息,不建议使用 http://forum.springsource.org/showthread.php?117227-Missing-Hibernate- Classes-Interfaces-in-spring
问题内容: 我正在将hibernate项目配置为使用第二级缓存提供程序,以便可以利用查询缓存。 我向ehcache添加了一个依赖项: 我认为我要使用的提供程序类是: 在eclipse中查看引用的库时,我在和上都看到了注释。是什么赋予了?我可以使用最新的替代供应商吗? 我正在使用hibernate版本3.4.0.GA,以防万一。 问题答案: 是什么赋予了?我可以使用最新的替代供应商吗? 不推荐使用它
问题内容: 我曾经在hibernate 3中使用getHibernateTemplate(),现在我转向了Hibernate 4,在这里我找不到以下类: 有人可以解释我为什么吗?在hibernate4中,我现在需要执行所有任务,例如提交,关闭,刷新由getHibernateTemplate()方法自动管理的事务? 问题答案: 因为它的主要目的是使Hibernate会话绑定到当前的Spring事务(
问题内容: 当您查看java.util.Date类的javadoc时,大多数方法都已弃用。为什么要这样做? 问题答案: 好吧,有两个相关原因。这是对日期和时间概念的非常差的实现,被班级取代。 该课程尽管有所改进,但也有很多不足之处,因此对于认真的Date / Time工作,每个人都推荐Joda- Time 。Java 8 引入了新的java.time。*软件包,该软件包受JSR-310定义的Jod
问题内容: HTML从早期开始就有框架,但是在最新版本中已弃用。许多浏览器(我曾尝试使用Internet Explorer)甚至无法正确显示框架。 为什么要这样做?镜框的缺点是什么? 问题答案: 雅各布·尼尔森(JakobNielsen)在1996年的专栏批评镜框。一些关键点: 框架会阻止用户正确标记页面。加载带有书签的框架集页面时,用户先前在框架内单击鼠标没有关系。仅保存外部URL,用户必须导航