问题
如何克隆anArrayList
并在Java中克隆其项目?
例如我有:
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....
我希望clonedList
中的对象与狗列表中的对象不同。
#1 热门回答(169 赞)
我个人会给Dog添加一个构造函数:
class Dog
{
public Dog()
{ ... } // Regular constructor
public Dog(Dog dog) {
// Copy all the fields of Dog.
}
}
然后迭代(如Varkhan的回答所示):
public static List<Dog> cloneList(List<Dog> dogList) {
List<Dog> clonedList = new ArrayList<Dog>(dogList.size());
for (Dog dog : dogList) {
clonedList.add(new Dog(dog));
}
return clonedList;
}
我发现这样做的好处是你不需要在Java中使用破解的Cloneable东西。它还与你复制Java集合的方式相匹配。
另一种选择可能是编写自己的ICloneable接口并使用它。这样你就可以编写一个通用的克隆方法。
#2 热门回答(168 赞)
你将需要迭代这些项目,并逐个克隆它们,然后将克隆放入结果数组中。
public static List<Dog> cloneList(List<Dog> list) {
List<Dog> clone = new ArrayList<Dog>(list.size());
for (Dog item : list) clone.add(item.clone());
return clone;
}
为了实现这一点,显然,你必须让Dog对象实现Cloneable接口和clone()方法。
#3 热门回答(119 赞)
所有标准集合都有复制构造函数。使用它们。
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
clone()
设计有几个错误(见this question),所以最好避免它。
从Effective Java 2nd Edition,第11项:明智地覆盖克隆
鉴于与Cloneable相关的所有问题,可以肯定地说其他接口不应该扩展它,并且为继承而设计的类(第17项)不应该实现它。由于它有许多缺点,一些专家程序员只是选择永远不要覆盖克隆方法,永远不要调用它,除非复制数组。如果你设计了一个继承类,请注意,如果你选择不提供行为良好的受保护克隆方法,则子类将无法实现Cloneable。
本书还介绍了复制构造函数相对于Cloneable / clone的许多优点。
- 他们不依赖于易于冒险的语言外对象创建机制
- 他们并不要求无法强制遵守精简文件的惯例
- 它们与正确使用最终字段不冲突
- 他们不会抛出不必要的检查异常
- 他们不需要演员阵容。
考虑使用复制构造函数的另一个好处:假设你有aHashSet s
,并且你希望将其复制为aTreeSet
。克隆方法无法提供此功能,但使用转换构造函数很容易:new TreeSet(s)
。