pal*_*lig 258 java collections clone deep-copy
如何克隆ArrayList
并在Java中克隆其项目?
例如,我有:
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....
Run Code Online (Sandbox Code Playgroud)
我希望那些物品clonedList
与狗列表中的物品不同.
Var*_*han 192
您将需要迭代这些项目,并逐个克隆它们,然后将克隆放入结果数组中.
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;
}
Run Code Online (Sandbox Code Playgroud)
为了实现这一点,显然,您必须让您的Dog
类实现Cloneable
接口并覆盖该clone()
方法.
cdm*_*kay 190
我个人会给Dog添加一个构造函数:
class Dog
{
public Dog()
{ ... } // Regular constructor
public Dog(Dog dog) {
// Copy all the fields of Dog.
}
}
Run Code Online (Sandbox Code Playgroud)
然后迭代(如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;
}
Run Code Online (Sandbox Code Playgroud)
我发现这样做的好处是你不需要在Java中使用破解的Cloneable东西.它还与您复制Java集合的方式相匹配.
另一种选择可能是编写自己的ICloneable接口并使用它.这样你就可以编写一个通用的克隆方法.
Ros*_*one 139
所有标准集合都有拷贝构造函数.使用它们.
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
Run Code Online (Sandbox Code Playgroud)
clone()
设计有几个错误(见这个问题),所以最好避免它.
从Effective Java 2nd Edition,第11项:明智地覆盖克隆
鉴于与Cloneable相关的所有问题,可以肯定地说其他接口不应该扩展它,并且为继承而设计的类(第17项)不应该实现它.由于它有许多缺点,一些专家程序员只是选择永远不要覆盖克隆方法,永远不要调用它,除非复制数组.如果您设计了一个继承类,请注意,如果您选择不提供行为良好的受保护克隆方法,则子类将无法实现Cloneable.
本书还介绍了复制构造函数相对于Cloneable/clone的许多优点.
考虑使用复制构造函数的另一个好处:假设您有一个HashSet s
,并且您希望将其复制为TreeSet
.克隆方法无法提供此功能,但转换构造函数很容易:new TreeSet(s)
.
Lii*_*Lii 38
Java 8提供了一种新方法,可以优雅紧凑地调用元素狗上的复制构造函数或克隆方法:Streams,lambdas和collectors.
复制构造函数:
List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList());
Run Code Online (Sandbox Code Playgroud)
该表达式Dog::new
称为方法引用.它创建了一个函数对象,该对象调用构造函数,在Dog
该构造函数上将另一个狗作为参
克隆方法[1]:
List<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList());
Run Code Online (Sandbox Code Playgroud)
ArrayList
结果或者,如果你需要ArrayList
退回(如果你想稍后修改它):
ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));
Run Code Online (Sandbox Code Playgroud)
如果您不需要保留dogs
列表的原始内容,则可以使用该replaceAll
方法并更新列表:
dogs.replaceAll(Dog::new);
Run Code Online (Sandbox Code Playgroud)
所有例子都假设import static java.util.stream.Collectors.*;
.
ArrayList
s可以将最后一个示例中的收集器制成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);
}
Run Code Online (Sandbox Code Playgroud)
CloneNotSupportedException
:对于此解决方案的工作clone
方法,Dog
必须不要声明它抛出CloneNotSupportedException
.原因是参数to map
不允许抛出任何已检查的异常.
像这样:
// Note: Method is public and returns Dog, not Object
@Override
public Dog clone() /* Note: No throws clause here */ { ...
Run Code Online (Sandbox Code Playgroud)
然而,这应该不是一个大问题,因为无论如何这是最好的做法.(例如,Effectice Java提供了这个建议.)
感谢Gustavo注意到这一点.
如果你发现它更漂亮,你可以使用方法引用语法来完成同样的事情:
List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
Run Code Online (Sandbox Code Playgroud)
jav*_*tar 27
基本上有三种方法没有手动迭代,
1使用构造函数
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);
Run Code Online (Sandbox Code Playgroud)
2使用 addAll(Collection<? extends E> c)
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(dogs);
Run Code Online (Sandbox Code Playgroud)
3使用addAll(int index, Collection<? extends E> c)
带int
参数的方法
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(0, dogs);
Run Code Online (Sandbox Code Playgroud)
注意:如果在操作过程中修改了指定的集合,则将不确定这些操作的行为.
Coj*_*nes 18
我认为目前的绿色答案很糟糕,为什么你会问?
序列化的方式也很糟糕,你可能需要在整个地方添加Serializable.
那么解决方案是什么:
Java深度 克隆库克隆库是一个小型的开源(apache许可证)java库,它深入克隆对象.对象不必实现Cloneable接口.实际上,这个库可以克隆任何java对象.如果您不希望修改缓存对象或者只是想要创建对象的深层副本,则可以在缓存实现中使用它.
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
Run Code Online (Sandbox Code Playgroud)
请访问https://github.com/kostaskougios/cloning查看
我找到了一种方法,您可以使用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());
Run Code Online (Sandbox Code Playgroud)
您也可以使用jackson和其他任何json库来实现。
我一直使用此选项:
ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
Run Code Online (Sandbox Code Playgroud)