Java:Cloneable接口的原理

33
为什么在java.lang.Cloneable接口中没有指定.clone()方法?
5个回答

36

基本上,它是一个损坏的接口。Ken Arnold和Bill Venners在Java设计问题中讨论了这个问题。

Arnold:

如果我此时成为上帝(很多人可能会高兴我不是),我会说弃用Cloneable并使用Copyable,因为Cloneable存在问题。除了它拼写错误之外,Cloneable没有包含clone方法。这意味着您无法测试某个对象是否为Cloneable的实例,将其强制转换为Cloneable,并调用clone方法。您必须再次使用反射,这很糟糕。这只是其中一个问题,但这是我肯定要解决的问题。


为什么 Java 8 没有修复它?难道之前没有移除或更改过 Java 的破损/无效部分吗? - DagdA
4
因为少数人这么说,就认为它是“破损的”吗?“Cloneable接口不包含克隆方法”,是的,它的文档从未这样说过。“这意味着你无法测试某个东西是否是Cloneable的实例,将其强制转换为Cloneable并调用clone。”再次强调,这根本不是Cloneable的目的。Cloneable只是用来使Object.clone()抛出异常或不抛出异常的。它从来不是一个让你调用clone的接口。也许Java如果有这样的接口会更好,但是缺乏这样一个接口不能使另一个接口(Cloneable)变得不完整。 - newacct
6
仅因为代码行为符合文档描述并不意味着它是一个好的接口。我猜,如果你的代码不能正常工作,你会修改文档吗? - Bill the Lizard

10

@EpicPandaForce 可能是因为我们不想在某些情况下模仿 C++。克隆应该谨慎使用,大多数情况下它无法实现您想要实现的功能。Java 中缺少的东西是具有 const 参数,但复制每个(可变)对象实例并不是一个好的解决方案。是的,Java 有一些糟糕的地方,这就是其中之一。使用 Kotlin / 数据类。 - Maarten Bodewes

6
在Java中,有一个叫做标记接口的概念。其中,Cloneable接口没有任何方法或字段,只用于标识可克隆的语义。
来自dev-x网站的内容:
通常在Java中你会遇到一些没有任何行为的接口,也就是空接口定义。这些被称为标记接口。Java API中一些标记接口的例子包括:
- java.lang.Cloneable - java.io.Serializable - java.util.EventListener

1
我不认为这是一个奇怪的概念。有时候能够看到某个东西是否可以作为替代类型是很有用的。正如其他人所说,Cloneable 是有问题的。 - John Topley
它们应该作为混合(mixins)操作。在像Java这样的强类型语言中,这并不是我最喜欢的机制,但对于Serializable来说是有意义的,可以这么说。 - wds
5
如果注解早在十年前就出现了,@Serializable 就更有意义了。至少它看起来是这样的。 - Tom Hawtin - tackline
我喜欢Tom的最后一条评论 :) 有很多特性在十年前就应该有了... - Peter Perháč

5
在我工作的项目中,我们创建了一个名为PublicCloneable的接口,它包含了clone方法并指定为public。
我认为这很有用:有一个clone方法,但是无法访问并没有什么帮助。
public interface PublicCloneable extends Cloneable {
    public Object clone();
}

1
如何使用这个接口(PublicConeable)? - Otto
@Otto:例如,一个CloneHelper类,其中有一个公共静态方法PublicCloneable copy(PublicCloneable obj),它检查null值,或者只是copy(Object obj),并检查null值和PublicCloneable实例。 - Nicolas C
当你从本地缓存中返回一个对象时,例如... 话虽如此,序列化/反序列化可能更安全。 - Nicolas C
2
“并指定为公共的。” - 实际上,接口中定义的方法默认为公共方法。在代码中不需要特别说明。@NicolasC - Mukit09

1
因为克隆方法是由Object类实现的,这是由于其“特殊”的条件:任何类型的对象的内存复制。

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