我该在Java中使用Clone方法吗?

9

我听说你应该避免在代码中使用它,但由于某些原因它被实现了,所以有没有使用它是一个好(或不错)选择的情况,或者我始终应该尽量避免使用它?


我不会说你应该避免它。像几乎所有的东西一样,你可以正确或错误地使用它...读一些关于原型模式的内容,这就是你如何正确使用它的方法... - Jaa-c
当不确定时,应该自己去实现,或者如果可能的话,最好查看源代码。使用clone()方法的主要问题是,您不能总是知道它是否按预期工作(除非您进行测试)。例如,我曾经很难获得一个int数组的克隆。然而,clone的文档说明应该返回对象的副本,所以我也在等待答案! - Olavi Mustanoja
2
我在17年的编程生涯中从未使用过它,也没有使用过“复制构造函数”。 - user207421
@EJP,你以前从未使用过新的ArrayList(list)复制构造函数吗?或者它的许多变体之一? - Afforess
@Afforess,这个构造函数并不存在。在我的书中,ArrayList(Collection<? extends E> c)不是一个复制构造函数,而ArrayList(ArrayList<? extends E> list)则是。我也不会称1998年引入的东西为“新”。 - user207421
1
@EJP,我不确定为什么您不认为ArrayList(Collection<? extends E> c)是一个复制构造函数,因为它执行的操作与ArrayList(ArrayList<? extends E> list)完全相同。如果看起来像鸭子,叫起来像鸭子,那么它很可能就是一只鸭子... - Afforess
2个回答

10

Josh Bloch非常完美地回答了这个问题:

如果您阅读了我的书中有关克隆的内容,特别是如果您在字里行间看出一些东西,那么您就会知道我认为克隆是极其不稳定的。存在一些设计缺陷,其中最大的问题是Cloneable接口没有克隆方法。这意味着它根本无法工作:将某物定义为Cloneable并不能说明您可以对其进行哪些操作。相反,它说明了它在内部可以做什么。它表示,如果通过重复调用super.clone,最终调用Object的克隆方法,那么该方法将返回原始字段的副本。

但是,它并没有说明您可以对实现Cloneable接口的对象进行哪些操作,这意味着您无法进行多态克隆操作。如果我有一个Cloneable数组,您可能会认为我可以遍历该数组并克隆每个元素以制作数组的深层副本,但我不能这样做。您无法将某物强制转换为Cloneable并调用克隆方法,因为Cloneable没有公共的克隆方法,Object也没有。如果您尝试将其强制转换为Cloneable并调用克隆方法,编译器将会说您正在尝试对对象调用受保护的克隆方法。

Cloneable的不稳定令人遗憾,但这种情况确实存在。最初的Java API是在紧迫的截止期限下非常快速地完成的,以满足即将关闭的市场窗口。最初的Java团队做得非常出色,但并非所有API都是完美的。Cloneable是一个弱点,我认为人们应该意识到它的局限性。


0

你应该尽量根据对象类型来重写克隆方法,因为Java的clone()方法并不总是按照你所期望的方式工作。

参见:深拷贝、浅拷贝、克隆


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