Java ArrayList clone() method or java.util.ArrayList.clone()
method is used to create a shallow copy of an ArrayList instance. We can also use this method to perform a deep copy of an ArrayList. In this post, we will learn how to use clone()
method with different examples.
1. ArrayList clone()
Below is the syntax of ArrayList clone() method:
public Object clone()
We can call this method on any ArrayList instance. It overrides the clone method in the Object class. It doesn’t take any parameter. The returns value is a clone or shallow copy of the caller ArrayList.
2. ArrayList clone() for Shallow Copy
As mentioned before, ArrayList clone() method is used to create a shallow copy of an ArrayList. A shallow copy points to the same reference as the original ArrayList. If a change is made on any ArrayList instance , it reflected the change on all other cloned instances. Let’s look at the below example program:
import java.util.ArrayList;
import java.util.Iterator;
class Main{
private static void printArrayList(ArrayList<StringBuilder> firstArrayList, ArrayList<StringBuilder> secondArrayList){
Iterator<StringBuilder> firstIterator = firstArrayList.iterator();
Iterator<StringBuilder> secondIterator = secondArrayList.iterator();
System.out.println("First ArrayList: ");
while(firstIterator.hasNext()){
System.out.println(firstIterator.next());
}
System.out.println("Second ArrayList: ");
while(secondIterator.hasNext()){
System.out.println(secondIterator.next());
}
}
public static void main(String[] args){
ArrayList<StringBuilder> firstArrayList = new ArrayList<>();
firstArrayList.add(new StringBuilder("Hello"));
ArrayList<StringBuilder> secondArrayList = (ArrayList<StringBuilder>)firstArrayList.clone();
printArrayList(firstArrayList, secondArrayList);
firstArrayList.get(0).append(" World !!");
System.out.println("After firstArrayList is changed: ");
printArrayList(firstArrayList, secondArrayList);
}
}
Both ArrayLists can hold elements of type <a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/StringBuilder.html" target="_blank" data-type="URL" data-id="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/StringBuilder.html" rel="noreferrer noopener">StringBuilder</a>
. The printArrayList
method is called to print these ArrayLists. The secondArrayList
is a shallow copy of firstArrayList
, i.e. it created this ArrayList by using the clone()
method on firstArrayList
. We are calling this printArrayList
method two times. The first time it is called after both ArrayLists are created and the second time after the content of firstArrayList is changed.
If you run this program, it will print the below output:
First ArrayList:
Hello
Second ArrayList:
Hello
After firstArrayList
is changed:
First ArrayList:
Hello
Second ArrayList:
Hello
As you can see here, both ArrayLists are changed if we change any element of these.
3. Deep Copy with clone() method
Deep copy differs from a shallow copy. It allocates separate memory for each variable. So, we can avoid accidental changes in any mutable variables like we have seen in the above example of shallow copy. Let’s look at the below program:
import java.util.Calendar;
import java.util.Date;
class Car {
private int id;
private Date createdAt;
public Car(int id, Date date) {
this.id = id;
this.createdAt = date;
}
public void setCreatedAt(Date date) {
this.createdAt = date;
}
public Date getCreatedAt(){
return this.createdAt;
}
public void setId(int id){
this.id = id;
}
@Override
protected Object clone() {
Car cloneCar;
try {
cloneCar = (Car) super.clone();
}catch(CloneNotSupportedException e){
cloneCar = new Car(this.id, this.createdAt);
}
cloneCar.setCreatedAt((Date) this.createdAt.clone());
return cloneCar;
}
public void printDetails(){
System.out.println("id: "+id+", createAt: "+createdAt.toString());
}
}
class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2021);
calendar.set(Calendar.MONTH, 4);
calendar.set(Calendar.DATE, 21);
Car firstCar = new Car(0, calendar.getTime());
Car secondCar = (Car)firstCar.clone();
firstCar.printDetails();
secondCar.printDetails();
firstCar.getCreatedAt().setTime(10234333);
firstCar.setId(3);
firstCar.printDetails();
secondCar.printDetails();
}
}
In this example, we are overriding the clone()
method of the Car class to change it to do a deep copy. It creates a new copy of the mutable variables, i.e. for the Date, and assigns it to the new clone variable. If you run this program, it will print the below output:
id: 0, createAt: Fri May 21 20:22:58 IST 2021
id: 0, createAt: Fri May 21 20:22:58 IST 2021
id: 3, createAt: Thu Jan 01 08:20:34 IST 1970
id: 0, createAt: Fri May 21 20:22:58 IST 2021
As you can see here, the variables are not changed in the clone object even after we change these in the original one.
3.1 Deep Copy of Collection using clone() Method
Creating a deep copy of a collection is easier than you think. We can simply create one new collection and clone all elements from the original collection to the new collection. For example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
class Main {
private static void printArrayList(ArrayList<String> arrayList){
for (String s : arrayList) {
System.out.println(s);
}
}
public static void main(String[] args) {
ArrayList<String> givenArraylist = new ArrayList<>(Arrays.asList("one", "two", "three"));
Iterator<String> iterator = givenArraylist.iterator();
ArrayList<String> cloneArrayList = new ArrayList<>();
while(iterator.hasNext()){
cloneArrayList.add(iterator.next());
}
printArrayList(givenArraylist);
printArrayList(cloneArrayList);
}
}
In this example, we are copying each element of givenArraylist
to cloneArrayList
. If you run this program, it will print the contents of both of these ArrayLists:
one
two
three
one
two
three
4. How do I clone a generic List in Java?
To clone a generic list in Java, we can simply use the clone()
method:
import java.util.ArrayList;
import java.util.Arrays;
class Main {
private static void printArrayList(ArrayList<String> arrayList){
for (String s : arrayList) {
System.out.println(s);
}
}
public static void main(String[] args) {
ArrayList<String> givenArraylist = new ArrayList<>(Arrays.asList("one", "two", "three"));
ArrayList<String> cloneArrayList = (ArrayList<String>)givenArraylist.clone();
printArrayList(givenArraylist);
printArrayList(cloneArrayList);
}
}
It will clone the content, but it will be a shallow copy. For a deep copy, you can use the above method to copy each element of one ArrayList to another. We can also do it using stream starting from Java 8:
import java.util.ArrayList;
import java.util.Arrays;
import static java.util.stream.Collectors.toList;
class Main {
private static void printArrayList(ArrayList<String> arrayList){
for (String s : arrayList) {
System.out.println(s);
}
}
public static void main(String[] args) {
ArrayList<String> givenArraylist = new ArrayList<>(Arrays.asList("one", "two", "three"));
ArrayList<String> cloneArrayList = (ArrayList<String>)givenArraylist.stream().collect(toList());
printArrayList(givenArraylist);
printArrayList(cloneArrayList);
}
}
This will clone the content, but it will be a shallow copy.
Summary
The ArrayList clone() method is useful to quickly create a clone of an ArrayList. If we have only immutable values in an ArrayList
, then we can use it without worrying about anything. But, if we have any mutable value, a deep copy is preferred.