可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How can I clone an ArrayList
and also clone its items in Java?
For example I have:
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....
And I would expect that objects in clonedList
are not the same as in dogs list.
回答1:
You will need to iterate on the items, and clone them one by one, putting the clones in your result array as you go.
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;
}
For that to work, obviously, you will have to get your Dog
class to implement the Cloneable
interface and override the clone()
method.
回答2:
I, personally, would add a constructor to Dog:
class Dog
{
public Dog()
{ ... } // Regular constructor
public Dog(Dog dog) {
// Copy all the fields of Dog.
}
}
Then just iterate (as shown in Varkhan's answer):
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;
}
I find the advantage of this is you don't need to screw around with the broken Cloneable stuff in Java. It also matches the way that you copy Java collections.
Another option could be to write your own ICloneable interface and use that. That way you could write a generic method for cloning.
回答3:
All standard collections have copy constructors. Use them.
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
clone()
was designed with several mistakes (see this question), so it's best to avoid it.
From Effective Java 2nd Edition, Item 11: Override clone judiciously
Given all of the problems associated with Cloneable, it’s safe to say
that other interfaces should not extend it, and that classes
designed for inheritance (Item 17) should not implement it. Because of
its many shortcomings, some expert programmers simply choose never to
override the clone method and never to invoke it except, perhaps, to
copy arrays. If you design a class for inheritance, be aware that if
you choose not to provide a well-behaved protected clone method, it
will be impossible for subclasses to implement Cloneable.
This book also describes the many advantages copy constructors have over Cloneable/clone.
- They don't rely on a risk-prone extralinguistic object creation
mechanism
- They don't demand unenforceable adherence to thinly documented conventions
- They don't conflict with the proper use of final fields
- They don't throw unnecessary checked exceptions
- They don't require casts.
Consider another benefit of using copy constructors: Suppose you have a HashSet s
, and you want to copy it as a TreeSet
. The clone method can’t offer this functionality, but it’s easy with a conversion constructor: new TreeSet(s)
.
回答4:
Java 8 provides a new way to call the copy constructor or clone method on the element dogs elegantly and compactly: Streams, lambdas and collectors.
Copy constructor:
List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList());
The expression Dog::new
is called a method reference. It creates a function object which calls a constructor on Dog
which takes another dog as argument.
Clone method[1]:
List<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList());
Getting an ArrayList
as the result
Or, if you have to get an ArrayList
back (in case you want to modify it later):
ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));
Update the list in place
If you don't need to keep the original content of the dogs
list you can instead use the replaceAll
method and update the list in place:
dogs.replaceAll(Dog::new);
All examples assume import static java.util.stream.Collectors.*;
.
Collector for ArrayList
s
The collector from the last example can be made into a util method. Since this is such a common thing to do I personally like it to be short and pretty. Like this:
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] Note on CloneNotSupportedException
:
For this solution to work the clone
method of Dog
must not declare that it throws CloneNotSupportedException
. The reason is that the argument to map
is not allowed to throw any checked exceptions.
Like this:
// Note: Method is public and returns Dog, not Object
@Override
public Dog clone() /* Note: No throws clause here */ { ...
This should not be a big problem however, since that is the best practice anyway. (Effectice Java for example gives this advice.)
Thanks to Gustavo for noting this.
PS:
If you find it prettier you can instead use the method reference syntax to do exactly the same thing:
List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
回答5:
Basically there are three ways without iterating manually,
1 Using constructor
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);
2 Using addAll(Collection<? extends E> c)
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(dogs);
3 Using addAll(int index, Collection<? extends E> c)
method with int
parameter
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(0, dogs);
NB : The behavior of these operations will be undefined if the specified collection is modified while the operation is in progress.
回答6:
I think the current green answer is bad , why you might ask?
- It can require to add a lot of code
- It requires you to list all Lists to be copied and do this
The way serialization is also bad imo, you might have to add Serializable all over the place.
So what is the solution:
Java Deep-Cloning library
The cloning library is a small, open source (apache licence) java library which deep-clones objects. The objects don't have to implement the Cloneable interface. Effectivelly, this library can clone ANY java objects. It can be used i.e. in cache implementations if you don't want the cached object to be modified or whenever you want to create a deep copy of objects.
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
Check it out at https://github.com/kostaskougios/cloning
回答7:
I have found a way, you can use json to serialize/unserialize the list. The serialized list holds no reference to the original object when unserialized.
Using 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());
You can do that using jackson and any other json library too.
回答8:
I have used this option always:
ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
回答9:
You will need to clone the ArrayList
by hand (by iterating over it and copying each element to a new ArrayList
), because clone()
will not do it for you. Reason for this is that the objects contained in the ArrayList
may not implement Clonable
themselves.
Edit: ... and that is exactly what Varkhan's code does.
回答10:
A nasty way is to do it with reflection. Something like this worked for me.
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<>();
}
}
回答11:
The other posters are correct: you need to iterate the list and copy into a new list.
However...
If the objects in the list are immutable - you don't need to clone them. If your object has a complex object graph - they will need to be immutable as well.
The other benefit of immutability is that they are threadsafe as well.
回答12:
Here is a solution using a generic template type:
public static <T> List<T> copyList(List<T> source) {
List<T> dest = new ArrayList<T>();
for (T item : source) { dest.add(item); }
return dest;
}
回答13:
for you objects override clone() method
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;
}
}
and call .clone() for Vector obj or ArraiList obj....
回答14:
Easy way by using commons-lang-2.3.jar that library of java to clone list
link download commons-lang-2.3.jar
How to use
oldList.........
List<YourObject> newList = new ArrayList<YourObject>();
foreach(YourObject obj : oldList){
newList.add((YourObject)SerializationUtils.clone(obj));
}
I hope this one can helpful.
:D
回答15:
The package import org.apache.commons.lang.SerializationUtils;
There is a method SerializationUtils.clone(Object);
Example
this.myObjectCloned = SerializationUtils.clone(this.object);
回答16:
I have just developed a lib that is able to clone an entity object and a java.util.List object. Just download the jar in https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U and use the static method cloneListObject(List list). This method not only clones the List but also all entity elements.
回答17:
The below worked for me..
in 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;
}
Here the new list which got created from createCopy method is created through SerializationUtils.clone().
So any change made to new list will not affect original list
回答18:
List<Dog> dogs;
List<Dog> copiedDogs = dogs.stream().map(dog -> SerializationUtils.clone(dog)).Collectors.toList());
This will deep copy each dog
回答19:
I think I found a really easy way to make a deep copy ArrayList. Assuming you want to copy a String ArrayList arrayA.
ArrayList<String>arrayB = new ArrayList<String>();
arrayB.addAll(arrayA);
Let me know if it doesn't work for you.