Java ArrayList clone() and Deep Copy Example

In Java, the ArrayList clone() method creates a shallow copy of the list in which only object references are copied. If we change the object state of a list item inside the first ArrayList, the changed object state will also be reflected in the cloned list.

To prevent changes reflected in both lists, we should explicitly create a deep copy of the list.

1. Using ArrayList.clone() for Shallow Copy

The clone() method creates a new ArrayList and then copies the backing array to cloned array. It creates a shallow copy of the given arraylist. In a shallow copy, the original list and the cloned list, both refer to the same objects in the memory.

ArrayList Shallow Copy

Let us see the internal implementation of the clone method.

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

The following Java program creates a shallow copy of an arraylist using clone() method.

ArrayList<String> arrayListObject = new ArrayList<>(List.of("A", "B", "C", "D")); 

ArrayList<String> arrayListClone =  (ArrayList<String>) arrayListObject.clone();  

2. Creating a Deep Copy of ArrayList

Creating a deep copy of a list is not straightforward. Java does not support deep copying by default. So we have to manually modify the code to enable the deep copying of classes and collections. In a deep copy of the list, the items referred from both lists are different instances in the memory.

ArrayList Deep Copy

3.1. Enable Deep Copying on List Item

To create a deep copy of any class, divide all the class members into two categories of mutable and immutable types.

  • All immutable field members can be used as it is. They don’t require any special treatment. e.g. primitive classes, wrapper classes and String class.
  • For all mutable field members, we must create a new object of member and assign its value to cloned object.

The idea is to return an immutable copy of the class from clone() method. Checkout the overridden clone() method in the following class:

public class Employee implements Cloneable {

    private Long id;
    private String name;
    private Date dob;		//Mutable field

    public Employee(Long id, String name, Date dob) {
        super();
        this.id = id;
        this.name = name;
        this.dob = dob;
    }

    //Getters and setters

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Employee clone = null;
        try  {
            clone = (Employee) super.clone();
            //Copy new date object to cloned method
            clone.setDob((Date) this.getDob().clone());
        }
        catch (CloneNotSupportedException e)  {
            throw new RuntimeException(e);
        }
        return clone;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]";
    }
}

3.2. Deep Copying a Java Collections

Creating a deep copy of a collection is rather easy. We need to create a new instance of collection and copy all elements from the given collection into the cloned collection – one by one. Note that we will copy the element’s clone in the cloned collection.

ArrayList<Employee> employeeList = new ArrayList<>(); 
ArrayList<Employee> employeeListClone = new ArrayList<>();
 
Collections.copy(employeeList, employeeListClone);

3.3. Demo

Java program to create a deep copy of an arraylist.

ArrayList<Employee> employeeList = new ArrayList<>(); 
employeeList.add(new Employee(1l, "adam", new Date(1982, 02, 12)));
 
ArrayList<Employee> employeeListClone = new ArrayList<>(); 
 
Collections.copy(employeeList, employeeListClone);
 
//Modify the list item in cloned list - it should affect the original list item
employeeListClone.get(0).setId(2l);
employeeListClone.get(0).setName("brian");
employeeListClone.get(0).getDob().setDate(13);;
 
System.out.println(employeeList); 
System.out.println(employeeListClone);   

Program output. Notice that even after changing the values of Employee object in employeeListClone, original employee list employeeList is not changed.

[Employee [id=1, name=adam, dob=Sun Mar 12 00:00:00 IST 3882]]

[Employee [id=2, name=brian, dob=Mon Mar 13 00:00:00 IST 3882]]

Happy Learning !!

Comments

Subscribe
Notify of
guest
2 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode