如何克隆ArrayList并克隆其内容?

我如何克隆一个ArrayList ,并克隆它的项目在Java中?

例如,我有:

 ArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = ....something to do with dogs.... 

我期望clonedList中的对象与狗列表中的不同。

您将需要遍历项目,并逐个克隆它们,随时将克隆放入结果数组中。

 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()方法。

我个人会给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集合的方式相匹配。

另一种select是编写你自己的ICloneable接口并使用它。 这样你可以写一个通用的克隆方法。

所有的标准集合都有复制构造函数。 使用它们。

 List<Double> original = // some list List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy 

clone()devise有几个错误(见这个问题 ),所以最好避免它。

从Effective Java 2nd Edition ,项目11: 明智地重写克隆

鉴于与Cloneable相关的所有问题,可以肯定的是,其他接口不应该扩展它,而为inheritancedevise的类(Item 17)不应该实现它。 由于它的许多缺点,一些专家程序员只是简单地select不覆盖克隆方法,除非可能复制数组,否则不要调用它。 如果您devise了inheritance类,请注意,如果您select不提供行为良好的受保护的克隆方法,那么子类就不可能实现Cloneable。

本书还介绍了复制构造函数对Cloneable / clone的许多优点。

  • 他们不依赖风险倾向的超语言对象创build机制
  • 他们不要求不可强制遵守稀less的文件规定
  • 它们不会与正确使用最终字段相冲突
  • 他们不会抛出不必要的检查exception
  • 他们不需要演员。

考虑使用复制构造函数的另一个好处:假设你有一个HashSet s ,并且你想把它复制为TreeSet 。 克隆方法不能提供这种function,但使用转换构造函数很容易: new TreeSet(s)

基本上有三种方法不需要手动迭代,

1使用构造函数

 ArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs); 

2使用addAll(Collection<? extends E> c)

 ArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = new ArrayList<Dog>(); clonedList.addAll(dogs); 

3用int参数使用addAll(int index, Collection<? extends E> c)方法

 ArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = new ArrayList<Dog>(); clonedList.addAll(0, dogs); 

注意:如果指定的集合在操作过程中被修改,这些操作的行为将是未定义的。

Java 8提供了一种新的方式来优雅地和紧凑地调用元素狗的复制构造函数或克隆方法: streamlambdas收集器

复制构造函数:

 List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList()); 

expression式Dog::new称为方法引用 。 它引用一个Dog的构造函数,以另一只狗作为参数。

克隆方法:

 List<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList()); 

作为结果得到一个ArrayList

或者,如果你必须返回一个ArrayList (如果你想稍后修改它):

 ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new)); 

更新列表

如果您不需要保留dogs列表的原始内容,则可以使用replaceAll方法并相应地更新列表:

 dogs.replaceAll(Dog::new); 

所有示例都假定import static java.util.stream.Collectors.*;


ArrayList的收集器

最后一个例子中的收集器可以变成一个util方法。 由于这是一个很普遍的事情,我个人喜欢它短而漂亮。 喜欢这个:

 ArrayList<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList()); public static <T> Collector<T, ?, ArrayList<T>> toArrayList() { return Collectors.toCollection(ArrayList::new); } 

关于CloneNotSupportedException注意事项:

对于此解决scheme, Dogclone方法不得声明它抛出CloneNotSupportedException 。 原因是map的参数不允许抛出任何检查的exception。

喜欢这个:

  // Note: Method is public and returns Dog, not Object @Override public Dog clone() /* Note: No throws clause here */ { ... 

不过这应该不是一个大问题,因为无论如何这是最好的做法。 ( Effectice Java例如给出了这个build议。)

感谢古斯塔沃注意到这一点。


PS:

如果你觉得它漂亮,你可以使用方法引用语法来做同样的事情:

 List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList()); 

我认为目前的绿色答案是不好的 ,为什么你会问呢?

  • 它可能需要添加大量的代码
  • 它要求您列出所有要复制的列表并执行此操作

序列化的方式也是不好的,你可能需要在所有地方添加Serializable。

那么解决scheme是什么?

Java深度克隆库克隆库是一个小型开源(apache许可证)java库,它可以深入克隆对象。 这些对象不必实现Cloneable接口。 有效地,这个库可以克隆任何Java对象。 如果您不希望caching的对象被修改,或者您想要创build对象的深层副本,则可以在caching实现中使用它。

 Cloner cloner=new Cloner(); XX clone = cloner.deepClone(someObjectOfTypeXX); 

通过https://github.com/kostaskougios/cloning查看;

一个讨厌的方法是用reflection来做。 这样的事情为我工作。

 public static <T extends Cloneable> List<T> deepCloneList(List<T> original) { if (original == null || original.size() < 1) { return new ArrayList<>(); } try { int originalSize = original.size(); Method cloneMethod = original.get(0).getClass().getDeclaredMethod("clone"); List<T> clonedList = new ArrayList<>(); // noinspection ForLoopReplaceableByForEach for (int i = 0; i < originalSize; i++) { // noinspection unchecked clonedList.add((T) cloneMethod.invoke(original.get(i))); } return clonedList; } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { System.err.println("Couldn't clone list due to " + e.getMessage()); return new ArrayList<>(); } } 

您将需要手工复制ArrayList (通过遍历它并将每个元素复制到一个新的ArrayList ),因为clone()不会为你做。 原因是ArrayList包含的对象可能Clonable实现Clonable

编辑 :…这正是Varkhan的代码。

这是另一种方法,大概是一个快速的方法: http : //javatechniques.com/blog/faster-deep-copies-of-java-objects/

其他海报是正确的:你需要迭代列表并复制到一个新的列表。

但是…如果列表中的对象是不可变的 – 你不需要克隆它们。 如果你的对象有一个复杂的对象图 – 它们也需要是不可变的。

不变性的另一个好处是它们也是线程安全的。

以下是使用通用模板types的解决scheme:

 public static <T> List<T> copyList(List<T> source) { List<T> dest = new ArrayList<T>(); for (T item : source) { dest.add(item); } return dest; } 

为你的对象重载clone()方法

 class You_class { int a; @Override public You_class clone() { You_class you_class = new You_class(); you_class.a = this.a; return you_class; } } 

并为Vector obj或ArraiList obj调用.clone()。

简单的方法是使用commons-lang-2.3.jar这个java库克隆列表

链接下载commons-lang-2.3.jar

如何使用

 oldList......... List<YourObject> newList = new ArrayList<YourObject>(); foreach(YourObject obj : oldList){ newList.add((YourObject)SerializationUtils.clone(obj)); } 

我希望这一个可以帮助。

:d

import org.apache.commons.lang.SerializationUtils;

有一个方法SerializationUtils.clone(Object);

 this.myObjectCloned = SerializationUtils.clone(this.object); 

我想我发现了一个真正简单的方法来创build一个深层复制ArrayList。 假设你想复制一个String ArrayList arrayA。

 ArrayList<String>arrayB = new ArrayList<String>(); arrayB.addAll(arrayA); 

让我知道如果它不适合你。

我刚刚开发了一个能够克隆实体对象和java.util.List对象的库。 只需在https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U中下载jar并使用静态方法cloneListObject(List list)即可。 这个方法不仅克隆List,还包括所有的实体元素。

我find了一种方法,你可以使用json序列化/反序列化列表。 序列化的列表在反序列化时不包含原始对象的引用。

使用gson:

 List<CategoryModel> originalList = new ArrayList<>(); // add some items later String listAsJson = gson.toJson(originalList); List<CategoryModel> newList = new Gson().fromJson(listAsJson, new TypeToken<List<CategoryModel>>() {}.getType()); 

你可以使用jackson和任何其他的JSON库。