为什么java.lang.Cloneable没有覆盖java.lang.Object中的clone()方法?

9
Java规范中的java.lang.Cloneable接口定义了任何扩展它的对象也实现了沉睡在java.lang.Object内部的clone()方法。具体来说,它表示:
一个类实现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:Cloneable接口的原理的重复。 - Matt Ball
2个回答

7
因为这是一个设计不良的界面。
来自Effective Java(抱歉,Google Books没有第二版的预览):

条款11:谨慎地覆盖clone

Cloneable接口旨在作为对象声明允许克隆的混合接口(条款18)。不幸的是,它未能达到这个目的。它的主要缺陷是它缺少一个clone方法,并且Objectclone方法是受保护的。您不能仅因为一个对象实现了Cloneable就使用反射(条款53)调用其clone方法。即使是反射调用也可能失败,因为没有保证对象具有可访问的clone方法。


2
它早该被改变了。然而,我认为永远不会改变,因为这将引入向后不兼容性。如果在Java 1.8中有一个“修复”,我想它会是类似于@Copyable注释的东西。 - Matt Ball
2
@SoboLAN 你希望如何更改它?删除它会导致很多兼容性问题,而收益却很小。将其添加到设计不良且不应使用的东西中,真的有必要吗? - Tom Hawtin - tackline
1
叹气:尽管我非常讨厌Cloneableclone,但我宁愿看到它们被弃用而不是直接删除。 - Louis Wasserman
我的意思是它应该被弃用或完全重构...我没有用对词...损失很小(因为目前极少使用),而收益相当可观(因为有很多使用案例...) - Radu Murzea
1
然而,Oracle 无法精确地重构所有 Java 用户的代码,其政策基本上是尽可能避免破坏外部代码。 - Louis Wasserman
显示剩余4条评论

7

呃,cloneCloneable 都是有问题、设计糟糕的东西,在新代码中不应该使用。 (请参考《Effective Java》第11条。)

造成这种情况的原因是,Cloneable 是一个实现混乱、神秘莫测的接口,仅仅实现了 Cloneable 这个接口就会通过反射改变 Object.clone 的行为。《Effective Java》这样说:

如果一个类实现了 Cloneable 接口,那么它的 clone 方法将返回一个按字段拷贝的对象;否则,它将抛出 CloneNotSupportedException 异常。这是接口的一种高度非典型用法,不应被模仿...


我认为反射与此无关(首先它的产生早于反射)。 - Tom Hawtin - tackline
哦,天啊,这太邪恶了。我猜clone的本地实现在内部执行了等效于反射的操作? - Louis Wasserman
根据Javadoc,“Object类的克隆方法执行特定的克隆操作。首先,如果此对象的类没有实现Cloneable接口,则会抛出CloneNotSupportedException异常。请注意,所有数组都被认为实现了Cloneable接口,并且数组类型T[]的克隆方法的返回类型是T[],其中T是任何引用或基本类型。否则,此方法将创建此对象类的新实例,并使用与此对象的相应字段的内容完全相同的内容初始化其所有字段,...” - Ky -
此方法执行的是“浅拷贝”操作,而非“深拷贝”操作。即使通过赋值进行了复制,字段的内容本身也不会被克隆。 - Ky -
是的,但它必须在本地执行Cloneable检查而非在Java中执行。 - Louis Wasserman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接