为啥 java.lang.Cloneable 不覆盖 java.lang.Object 中的 clone() 方法?
Posted
技术标签:
【中文标题】为啥 java.lang.Cloneable 不覆盖 java.lang.Object 中的 clone() 方法?【英文标题】:Why does java.lang.Cloneable not override the clone() method in java.lang.Object?为什么 java.lang.Cloneable 不覆盖 java.lang.Object 中的 clone() 方法? 【发布时间】:2012-04-16 10:19:27 【问题描述】:java.lang.Cloneable
接口的 Java 规范将其自身定义为表示扩展它的任何对象也实现了 clone()
方法,该方法在 java.lang.Object
中处于休眠状态。具体来说,它说:
一个类实现了
Cloneable
接口,以向java.lang.Object#clone()
方法指示该方法对该类的实例进行逐个字段的复制是合法的。
对我来说,这意味着应该假设每个扩展 Cloneable
的类因此在其中也有一个 public Object clone()
方法。这使得很容易假设以下方法是有效的:
public static makeACloneFrom(Cloneable c)
return c.clone();
然而,情况并非如此,因为整个 Cloneable
源代码(无 javadoc)只是
package java.lang;
public interface Cloneable
这意味着Cloneable#clone()
不存在(并且尝试编译上面的示例方法会引发编译时错误,例如“cannot find symbol: method clone()
”)。 Cloneable
的源代码不应该包含public Cloneable clone();
的效果吗?
为什么我们不允许假设实现 Cloneable
的类具有 public Cloneable clone()
方法?
【问题讨论】:
Java: Rationale of the Cloneable interface 的可能重复项 【参考方案1】:因为它是一个设计糟糕的界面。
来自Effective Java(抱歉,Google 图书没有第二版的预览):
第 11 项:明智地覆盖
clone
Cloneable
接口旨在作为一个 mixin 接口(项目 18) 让对象宣传它们允许克隆。很遗憾, 它不能达到这个目的。它的主要缺陷是缺乏clone
方法和Object
的clone
方法受到保护。你 不能通过 reflection(第 53 项)调用clone
对象上的方法仅仅是因为它实现了Cloneable
。甚至一个 反射调用可能会失败,因为不能保证 对象有一个可访问的clone
方法。
【讨论】:
...所以,差不多,这应该在 Java 1.8 中改变? 它应该在 很久 之前就已更改。然而,我认为它永远不会,因为它会引入向后不兼容。如果在 Java 1.8 中有一个“修复”,我想它会类似于@Copyable
注释。
@SoboLAN 您希望如何更改?删除它会导致很多兼容性问题而收效甚微。添加到设计不佳且您不应该使用的东西,真的吗?
::sigh:: 尽管我很讨厌 Cloneable
和 clone
,但我宁愿看到它们被弃用,也不愿被彻底删除。
尽管如此,Oracle 不能完全重构所有 Java 用户的代码,它的策略是不惜一切代价基本上避免破坏外部代码。【参考方案2】:
呃。 clone
和 Cloneable
已损坏,设计糟糕,不应在新代码中使用。 (请参阅有效的 Java 项目 11。)
造成这种特殊情况的原因是 Cloneable
是一个令人困惑的实现,神奇的接口,因此仅仅实现 Cloneable
的行为就会通过反射改变 Object.clone
的行为。有效的 Java 说:
...如果一个类实现了
Cloneable
,Object
的clone
方法返回对象的逐字段副本;否则会抛出 CloneNotSupportedException。这是一种非常不典型的接口用法,不是要模拟的……
【讨论】:
我不认为反射与它有任何关系(它早于一件事的反射)。 天哪,这更邪恶。我猜clone
的本机实现在内部做了相当于反射的事情?
根据Javadoc,“类Object的方法clone执行特定的克隆操作。首先,如果该对象的类没有实现接口Cloneable,则抛出CloneNotSupportedException。注意所有数组被认为实现了接口 Cloneable 并且数组类型 T[] 的克隆方法的返回类型是 T[] 其中 T 是任何引用或原始类型。否则,此方法会创建此类的新实例对象并使用该对象的相应字段的内容来初始化其所有字段,...
... 好像被分配了;字段的内容本身不会被克隆。因此,此方法执行此对象的“浅拷贝”,而不是“深拷贝”操作。”
是的,但它必须这样做 Cloneable
在本机而不是在 Java 中检查。以上是关于为啥 java.lang.Cloneable 不覆盖 java.lang.Object 中的 clone() 方法?的主要内容,如果未能解决你的问题,请参考以下文章