Java中关于可克隆接口和object.clone()的混淆

19
如果我有:
class foo implements Cloneable

然后执行:

bar = new foo();
bar.clone();

我获得了一个浅拷贝,而不需要编写任何类似于我通常在实现接口时需要编写的bar.clone()代码。

我的理解是,接口的函数必须由实现它的类填充,而Object.clone()没有实现(根据文档,“类 Object 本身不实现 Cloneable 接口”)

那么我浅拷贝的来源是什么?如果Object.clone()没有实现,哪里有实现bar.clone()的代码?我感到困惑。

4个回答

29

使用克隆(clone)时要非常小心,事实上,我会完全避免使用它。我从未需要过它。但是...话虽如此,我曾读过有关该主题的最佳讨论,那就是由Joshua Bloch在《Effective Java》中写的第11条“明智地覆盖克隆方法(Override clone judiciously)”。

请务必自我保护并阅读这个条目。我真诚建议读完整个章节(以及整本书)。有关克隆和为什么我要警告你注意它的一切都在其中。

希望这能帮到你。


3
对于《Effective Java》的推荐给予+1。其中关于克隆的讨论非常出色,整本书也是如此。 - Jim Ferrans
这几乎应该是唯一的答案。鉴于Joshua Bloch对Cloneable中固有设计缺陷的出色讨论,几乎可以说这只是Java中的一个设计错误。你几乎总是最好使用复制构造函数/静态工厂。 - Visionary Software Solutions

7

Object.clone()有一个实现:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#clone()

这个链接解释了Cloneable接口:http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Cloneable.html

为了调用clone()方法,对象必须实现Cloneable接口,否则会抛出CloneNotSupportedException异常。

按照定义,Java中的所有类都扩展自基本的Object类,而Object类有一个默认的clone()方法,即使Object本身没有实现Cloneable接口。如果您不覆盖它自己,将调用Object类的clone()方法。


啊,我明白了。我误读了文档——对象确实有clone()的代码,只是它没有实现Cloneable接口。那么,强制实现Cloneable接口以调用class.clone()的机制是什么?这只是JRE知道要有意检查的东西吗? - ambertch
快速的答案——什么都没有。接口决定了对象的clone()实现行为。如果一个类是Cloneable,Object.clone()返回一个副本,否则它会抛出CloneNotSupportedException异常。Cloneable接口基本上修改了其超类的clone()实现行为。 - Cambium

1
如果我有:"class foo implements cloneable",然后执行:bar = new foo(); bar.clone(); 我会得到一个浅拷贝,而不需要编写任何bar.clone()代码,就像我通常需要实现接口时那样。
这只适用于在类“foo”内调用它,因为从Object继承的.clone()方法是受保护的。
我的理解是,接口的函数必须由实现它的类填充,而Object.clone()没有实现(根据文档,“类Object本身不实现接口Cloneable”)

(1) Object.clone()确实有实现。如果对象实现了Cloneable,它将对对象进行浅复制。(2).clone()方法不是任何接口的一部分。(3)拥有.clone()方法和实现Cloneable接口是完全不同的事情。您只需要实现Cloneable接口,如果您打算使用Objectclone方法。然而,这是编写类的clone方法的推荐方式-从超类的clone方法获取其副本,最终到达Objectclone方法。


谢谢,是的,你说得对 - 我错了,因为我误读了这句话,并将“implements coneable”与“有一个实现”混淆了。 - ambertch
为什么“只有在类“foo”内调用它时才有效,因为从Object继承的.clone()方法是受保护的。”如果我的子类调用foo.clone()呢?这完全是可能的,对吧? - amarnath harish
我从未提到subfoo在不同的包中,所以我猜它可以从相同的包中访问而无需担心。 - amarnath harish
包学习;public class foo实现Cloneable { /**
  • @param args */ public static void main(String[] args) { // TODO Auto-generated method stub
} protected foo clone() throws CloneNotSupportedException{ return new foo(); }} class subfoo扩展foo实现Cloneable { public static void main(String[] args) { // TODO Auto-generated method stub foo f = new foo(); try { f.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }这里我没有说foo没有实现clone。
- amarnath harish
@amarnathharish:据我理解,问题是关于当foo没有实现clone()方法时。 - newacct
显示剩余4条评论

1
我的理解是,接口的函数必须由实现它的类填写,而Object.clone()没有实现(根据文档,“类Object本身不实现接口Cloneable”)
说“Object.clone()没有实现”和“Object类本身不实现接口Cloneable”是有区别的。
Object的克隆方法确实有实现,它对调用克隆方法的对象进行内存复制。
你是对的,Object类不实现可克隆性,它只是检查对象是否可克隆。
上面的答案指向你阅读一些书,我想我可以给出一个快速的解决方案来回答你的问题
那么我的浅克隆是从哪里来的? 是从Object的clone方法来的。
如果Object.clone()没有实现,那么实现bar.clone()的代码在哪里? 它有实现,是用本地代码编写的。

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