我如何克隆一个数组列表,也克隆其项目在Java?

例如,我有:

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

我希望clonedList中的对象与dogs list中的对象不一样。


当前回答

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

1使用构造函数

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

2使用addAll(Collection<?c)扩展;

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

3使用addAll(int index, Collection<?用int形参扩展E> c)方法

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

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

其他回答

Java 8提供了一种优雅而简洁地调用元素狗的复制构造函数或克隆方法的新方法:流、lambdas和收集器。

拷贝构造函数:

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

表达式Dog::new被称为方法引用。它创建了一个函数对象,调用Dog上的构造函数,该构造函数以另一个Dog作为参数。

克隆方法[1]:

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

得到一个数组列表作为结果

或者,如果你必须得到一个数组列表(以防你以后想修改它):

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

及时更新列表

如果你不需要保留狗列表的原始内容,你可以使用replaceAll方法并在适当的地方更新列表:

dogs.replaceAll(Dog::new);

所有示例都假设导入静态java.util.stream.Collectors.*;


数组列表收集器

上一个例子中的收集器可以被做成一个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);
}

[1] CloneNotSupportedException异常说明:

为了使这个解决方案工作,Dog的克隆方法不能声明它抛出CloneNotSupportedException。原因是map的参数不允许抛出任何受控异常。

是这样的:

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

然而,这应该不是一个大问题,因为这是最佳实践。(例如,effective Java给出了这个建议。)

感谢Gustavo注意到这一点。

您可以使用JSON(带有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());

你也可以使用其他JSON库,比如Jackson。

使用这种方法的优点是可以解决问题,而不必创建类、接口和克隆逻辑(如果对象内部有其他对象列表,克隆逻辑可能会很长)

下面是一个使用泛型模板类型的解决方案:

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

下面的方法对我有用。

在Dog.java

public Class Dog{

private String a,b;

public Dog(){} //no args constructor

public Dog(Dog d){ // copy constructor
   this.a=d.a;
   this.b=d.b;
}

}

 -------------------------

 private List<Dog> createCopy(List<Dog> dogs) {
 List<Dog> newDogsList= new ArrayList<>();
 if (CollectionUtils.isNotEmpty(dogs)) {
 dogs.stream().forEach(dog-> newDogsList.add((Dog) SerializationUtils.clone(dog)));
 }
 return newDogsList;
 }

在这里,由createCopy方法创建的新列表是通过SerializationUtils.clone()创建的。 因此,对新列表所做的任何更改都不会影响原始列表

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