我理解Java克隆是如何工作的以及反对使用它的论据。让我们说无论如何我已经死了。
为了方便起见,我想为类Foo编写一个克隆方法,如下所示:
@Override
public Foo clone(){
Foo f = (Foo)super.clone();
//Replace mutable fields
return f;
}
据我所知,这是安全的。但是,我注意到API中的Cloneable类不会这样做。这有什么原因,是不是很糟糕?
答案 0 :(得分:17)
在Java 5之前,根本不允许使用协变返回类型,因此Foo clone()
甚至不会编译。
由于很久以前已经编写了很多Cloneable
类,这可能是大多数情况的原因。
我怀疑新类没有使用它只是因为已知clone()
非常少,而当人们很少使用它时,他们甚至不认为他们可以使用它。他们找到了一些“如何实现clone()”的问题并以老式的方式编写代码。
答案 1 :(得分:3)
Object.clone()
创建一个新对象,其中所有字段都与原始字段具有相同的值。对于引用类型的字段,这意味着新字段只是对与原始字段相同的对象的引用。它没有clone
个字段。因此,在许多情况下,默认实现将导致共享数据,这可能是不期望的。例如,如果ArrayList.clone()
使用了默认实现,那么最终会有两个ArrayList
个实例共享相同的后备数组。
如果对象的所有字段都是不可变的,那么简单地将super.clone()
的结果转换为适当的类型可能是个好主意。
答案 2 :(得分:3)
嗯,这绝对不是一个糟糕的风格,事实上,自从java 1.5发布以来你最好这样做,因为协变返回类型是 作为泛型的一部分在1.5版中引入,通过这样做,您可以更容易地使用API(不需要进行转换)。
source(Effective java 2nd edition)。