如何轻松克隆容器(例如ArrayList)?使用.clone()方法是否有问题?

3

我对于克隆ArrayList(Vector替代品)的解决方案,或许有些天真,是:

ArrayList<Double> alBis = (ArrayList<Double>) alOriginal.clone();

考虑到数组包含不可变的Double,我不需要克隆它们,只需要克隆容器。
由于clone()返回一个Object,所以我进行了类型转换,但是-Xlint会抱怨这是一个未经检查的转换。
那现在怎么办?用supressWarnings忽略它吗?创建一个新的ArrayList并使用紧凑的for循环复制原始元素?是否有类似于Arrays.copyOf()的库方法?
我阅读了Unchecked cast warning,但被接受的方式难以置信复杂。
3个回答

14

clone()存在严重的缺陷,参见此问题。不要使用它!

相反,所有标准集合都有复制构造函数。请使用它们:

List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);

参考资料:


阅读 Joshua Bloch 的《Effective Java》。 - Sean Patrick Floyd
在考虑使用克隆(clone)和拷贝构造函数(copy constructor)时,我们需要考虑如果传入的对象是从预期类派生出来的情况下应该发生什么。对于克隆而言,新对象将与原始对象属于同一类;而对于拷贝构造函数而言,新对象将属于预期的类。在某些情况下,其中一种行为是正确的,而另一种则明显错误,在不同的情况下需要不同的行为。 - supercat
按照同样的逻辑(克隆不受任何接口支持),使用clone()也违反了Effective Java Item 52:“通过它们的接口引用对象”。 - Sean Patrick Floyd
@Sean:如果一个可扩展的类Foo支持克隆,而从Foo派生的Bar也支持克隆,则接受Foo的例程即使它是Bar也可能尝试克隆它。在许多这样的情况下,克隆操作产生的新对象应该是Bar。如果需要的是一个Foo,其Foo-ish属性与Bar的属性匹配,并且剥离了Bar特定的属性,则复制构造函数可能是适当的,但否则我建议Clone在99.44%的情况下返回与原始对象相同的实际类型的对象。 - supercat
@supercat a) 是的,这就是他们设计克隆机制时的想法。但同样的人现在告诉我们这个过程存在缺陷。 b) 在问题的背景下没有层次结构。ArrayList 几乎不应该被子类化,它的父类也不支持 clone()。 - Sean Patrick Floyd
显示剩余2条评论

4

使用.clone()方法是否有问题?

尽可能避免使用它。它是一个过时的、设计不良且基本上是有缺陷的API。最好像@Sean建议的那样使用复制构造函数。


1

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