人们普遍认为Java中的Cloneable
接口已被破坏。这有很多原因,我不会提及; others已经做到了。它也是Java architects自己的位置。
我的问题是:为什么还没有被弃用?如果核心Java团队已经确定它已被破坏,那么他们也必须考虑弃用。他们这样做的原因是什么(在Java 8中它是still not deprecated)?
答案 0 :(得分:118)
1997年向bug提交了Java Bug Database关于向clone()
添加Cloneable
方法的问题,因此它将不再无用。它以解决方案关闭了#34;赢得了修复"理由如下:
Sun的技术审查委员会(TRC)详细审议了这个问题 并建议不要采取除改进之外的任何行动 当前Cloneable接口的文档。这是完整的 建议的文本:
现有的Java对象克隆API存在问题。有一个 受保护的"克隆" java.lang.Object上的方法,并且有一个接口 java.lang.Cloneable。意图是如果一个班级想要允许 其他人克隆它,那么它应该支持Cloneable 接口并使用a覆盖默认的受保护克隆方法 公共克隆方法。不幸的是,原因很方便 在时间的迷雾中,Cloneable接口没有定义克隆 方法
这种组合导致了相当多的混乱。一些课程 声称支持克隆,但不小心忘了支持 克隆方法。开发人员对Cloneable的假设感到困惑 工作和克隆应该做什么。
不幸的是,添加"克隆" Cloneable的方法是一个 不相容的变化。它不会破坏二进制兼容性,但它会 打破源兼容性。轶事证据表明,在 练习有很多类支持的情况 可克隆的接口但无法提供公共克隆方法。后 讨论,TRC一致建议我们不要修改 现有的Cloneable接口,因为兼容性影响。
另一个提议是添加新界面 java.lang.PubliclyCloneable以反映原始的预期目的 可克隆的以5比2多数,TRC建议不要这样做。 主要担心的是,这会增加更多的混乱(包括 拼写混乱!)到已经混乱的画面。
TRC一致建议我们添加额外的 现有Cloneable接口的文档,以便更好地描述 如何使用和描述"最佳实践"对于 实现者。
所以,虽然这不是直接关于已弃用的,但是没有使Cloneable"弃用"是技术评论委员会决定修改现有文档足够使这个界面有用。所以他们做到了。在Java 1.4之前,Cloneable
记录如下:
一个类实现Cloneable接口以指示 Object.clone()方法,该方法的合法性 该类的实例的field-for-field副本。
尝试克隆未实现Cloneable的实例 接口导致异常CloneNotSupportedException 抛出。
Cloneable接口声明没有方法。
从Java 1.4(2002年2月发布)到当前版本(Java 8),它看起来像这样:
一个类实现Cloneable接口以指示 Object.clone()方法,该方法的合法性 该类的实例的field-for-field副本。调用对象 克隆方法在未实现Cloneable的实例上 接口导致异常CloneNotSupportedException 抛出。
按照惯例,实现此接口的类应该重写 使用公共方法的Object.clone(受保护)。看到 Object.clone()有关重写此方法的详细信息。
请注意,此接口不包含克隆方法。因此, 仅仅凭借这一事实就无法克隆对象 它实现了这个接口。即使调用了clone方法 反过来说,不能保证它会成功。
答案 1 :(得分:63)
简短回答“为什么Cloneable
不被弃用?” (或者实际上,为什么X
不被弃用,对于任何X
而言,是因为没有太多关注弃用它们。
最近弃用的大多数内容都已弃用,因为有一个特定的计划要删除它们。例如,LogManager的addPropertyChangeListener
和removePropertyChangeListener
方法是deprecated in Java SE 8,目的是在Java SE 9中删除它们。(原因是它们不必要地复杂了模块的相互依赖性。 )实际上,这些API已经是removed from early JDK 9开发版本。 (请注意,类似的属性更改侦听器调用也已从Pack200
中删除;请参阅JDK-8029806。)
Cloneable
和Object.clone()
没有类似的类似计划。
更长的答案将涉及讨论更多问题,例如人们可能期望在这些API上发生的事情,如果平台被弃用会产生什么样的成本或收益,以及在API被弃用时与开发人员沟通的内容。我在最近的JavaOne演讲Debt and Deprecation中探讨了这个主题。 (该链接可用的幻灯片; video here。)事实证明,JDK本身在使用弃用方面并不十分一致。它曾被用来表示几种不同的东西,包括例如
这很危险,您应该了解使用它的风险(例如:Thread.stop()
,Thread.resume()
和Thread.suspend()
)。
这将在以后的版本中删除
java.util.Date
中的许多方法)所有这些都是不同的含义,它们的不同子集适用于不同的不赞成的东西。其中一些子集适用于未弃用的内容(但可能应该弃用)。
Cloneable
和Object.clone()
因其设计缺陷而难以正确使用而被“破坏”。但是,clone()
仍然是复制数组的最佳方法,而克隆对于精心实现的类实例的副本有一些有限的用处。删除克隆将是一个不兼容的变化,会破坏很多东西。克隆操作可以以不同的方式重新实现,但它可能比Object.clone()
慢。
但是,对于大多数情况,复制构造函数优于克隆。因此,将Cloneable
标记为“过时”或“取代”或类似的东西可能是合适的。这将告诉开发人员他们可能想要寻找其他地方,但它不会表明在将来的版本中可能会删除克隆机制。不幸的是,没有这样的标记。
就目前情况而言,“弃用”似乎意味着最终被删除 - 尽管事实上已经删除了少量已弃用的功能 - 因此克隆机制似乎不值得推荐。也许在将来可以应用替代标记,指导开发人员使用替代机制。
<强>更新强>
我在bug report添加了一些额外的历史记录。早期的JVM实现者和JVM规范的共同作者Frank Yellin在other answer引用的TRC建议中回应了“迷失在时间之中”的评论。我在这里引用了相关部分;完整的消息在错误报告中。
Cloneable没有方法与Serializable没有相同的原因。 Cloneable表示类的属性,而不是具体说明该类支持的方法。
在反射之前,我们需要一个本机方法来制作一个Object的浅表副本。因此,Object.clone()诞生了。很明显,许多类都希望覆盖此方法,并不是每个类都希望被克隆。因此Cloneable的诞生是为了表明程序员的意图。
所以,简而言之。 Cloneable的目的不是表明你有一个公共的clone()方法。这表明你愿意使用Object.clone()进行克隆,并且由实现决定是否公开clone()。
答案 2 :(得分:-1)
为什么它还没有被弃用?
因为JCP认为不合适,所以可能永远不会这样做。问问他们。你在错误的地方提问。
在Java API中保留此内容的原因是什么?
由于向后兼容性要求,没有人会从Java API中删除任何内容。最后一次发生的是1996/7年AWT事件模型在1.0和1.1之间的变化。