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.
Let us see the internal implementation of the clone method.
public Object clone() < try < ArrayListv = (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 arrayListObject = new ArrayList<>(List.of("A", "B", "C", "D")); ArrayList arrayListClone = (ArrayList) 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.
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 employeeList = new ArrayList<>(); ArrayList employeeListClone = new ArrayList<>(); Collections.copy(employeeList, employeeListClone);
Java program to create a deep copy of an arraylist.
ArrayList employeeList = new ArrayList<>(); employeeList.add(new Employee(1l, "adam", new Date(1982, 02, 12))); ArrayList 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]]
Java Array Copy – Deep Copy and Shallow Copy
Learn to create an array copy in Java. We will learn to shallow copy and deep copy an array with easy-to-follow examples.
1. Creating a Shallow Copy of Array
In shallow copying, the references of the array items are copied into the new array, so any change in the array or the array items is visible on the cloned copied array. The array.clone() method creates a shallow copy.
Let us go through a few methods that create shallow copies of an array in Java.
1.1. Using Object.clone() Method
In Java, to create a clone of an array, we should use array.clone(). It creates a shallow copy of the array. The default cloning always creates a shallow copy of the array. Any change (in the original array) will also be reflected in the cloned array.
Employee[] clonedArray = empArray.clone();
Let us see an example. When we made changes to empArray items, the items in the clonedArray are also changed.
Employee[] empArr = new Employee[2]; //Original array empArr[0] = new Employee(100, "Lokesh", "Gupta", new Department(1, "HR")); empArr[1] = new Employee(200, "Pankaj", "Kumar", new Department(2, "Finance")); Employee[] clonedArray = empArray.clone(); //Shallow copied array empArray[0].setFirstName("Unknown"); empArray[0].getDepartment().setName("Unknown"); System.out.println(empArray[0].getFirstName()); //Unknown System.out.println(empArray[0].getDepartment().getName()); //Unknown System.out.println(clonedArray[0].getFirstName()); //Unknown System.out.println(clonedArray[0].getDepartment().getName()); //Unknown
The Arrays.copyOf(array, newLength) method copies the specified array, truncating or padding with default values, so the copies array has the specified newLength.
The copyOf() is an overloaded method, so the default value to be filled in empty places depends on the type of elements in the array. For example, a boolean array will be filled with false and int array will be filled with 0. Object types will be filled with nulls.
Employee[] empArr = new Employee[2]; Employee[] copiedArray = Arrays.copyOf(empArray, empArr.length);
Another useful method provided by JDK. It is a native method and is also invoked within Arrays.copyOf() method, internally. But it makes code a little less readable due to multiple arguments used for invocation.
The arraycopy() method copies the items from srcArray (starting position srcPos) into destArray (starting position destPos). The count of items to be copied is specified using the length argument.
public static native void arraycopy(Object srcArray, int srcPos, Object destArray, int destPos, int length);
In the following example, all items from names array are copied into copyOfNames array, starting from position zero in both arrays.
String[] names = ; String[] copyOfNames = new String[names.length]; System.arraycopy(names, 0, copyOfNames, 0, copyOfNames.length); System.out.println(Arrays.toString(names)); //[Alex, Brian, Charles, David] System.out.println(Arrays.toString(copyOfNames)); //[Alex, Brian, Charles, David]
2. Creating a Deep Copy of Array
In deep copying, new instances of the array items are created, so any change to the original array does not reflect on the copied array. In-memory serialization is a shortcut approach for creating deep copies of an object in Java.
If you want to create a deep copy of an array in Java, then use Apache Common’s SerializationUtils.clone( array) method.
Employee[] copiedArray = SerializationUtils.clone(empArray); //Deep copied array
Let us verify with an example.
Employee[] empArray = new Employee[2]; empArray[0] = new Employee(100, "Lokesh", "Gupta", new Department(1, "HR")); empArray[1] = new Employee(200, "Pankaj", "Kumar", new Department(2, "Finance")); Employee[] copiedArray = SerializationUtils.clone(empArray); //Deep copied array empArray[0].setFirstName("Unknown"); empArray[0].getDepartment().setName("Unknown"); //Verify the change in original array - "CHANGED" System.out.println(empArray[0].getFirstName()); //Unknown System.out.println(empArray[0].getDepartment().getName()); //Unknown //Verify the change in deep copied array - "UNCHANGED" System.out.println(copiedArray[0].getFirstName()); //Lokesh System.out.println(copiedArray[0].getDepartment().getName()); //HR
Deep Copy an Array in Java
- Deep Copy Using the System.arraycopy() Function in Java
- Deep Copy an Array Using the Arrays.copyOf Command in Java
In this tutorial, we discuss how to deep copy an array in Java.
Generally, there are two types of array copy methods in Java: the Shallow Copy and the Deep Copy. In Shallow copy, the objects are copied. On the other hand, all the items are copied while a different array is created in Deep Copy.
Below is an example that shows what happens when we copy an array into another directly. We create an array arr1 with items and then initialize another arr2 with arr1 . When any element of arr2 is changed, the change also gets reflected to arr1 .
import java.util.Arrays; public class DeepCopy public static void main(String[] args) int[] arr1 = 10, 20, 30>; System.out.println("arr1 Before copying: " + Arrays.toString(arr1)); int[] arr2 = arr1; System.out.println("arr2 After copying: " + Arrays.toString(arr1)); arr2[0] = 30; System.out.println("arr1 after copying and changing an element in arr2: " + Arrays.toString(arr1)); > >
arr1 Before copying: [10, 20, 30] arr2 After copying: [10, 20, 30] arr1 after copying and changing an element in arr2: [30, 20, 30]
Deep Copy Using the System.arraycopy() Function in Java
In the following example, we take an array arr1 with a few items and then take another array arr2 and give it the size equal to that of arr1 . We call the arrayCopy() method of the System class that copies an array to another.
The arrayCopy() function takes four arguments; the first two are the source array and the starting position of copy in the source array. The third argument is the destination array and its starting position, where we’ll copy elements, and the number of items to be copied in a new array.
When we change the arr2 item, just like in the previous example, the elements of arr1 don’t change at all.
import java.util.Arrays; public class DeepCopy public static void main(String[] args) int[] arr1 = 10, 20, 30>; System.out.println("arr1 Before copying: " + Arrays.toString(arr1)); int[] arr2 = new int[arr1.length]; System.arraycopy(arr1, 0, arr2, 0, arr1.length); System.out.println("arr2 After copying: " + Arrays.toString(arr1)); arr2[0] = 30; System.out.println("arr1 after copying and changing an element in arr2: " + Arrays.toString(arr1)); > >
arr1 Before copying: [10, 20, 30] arr2 After copying: [10, 20, 30] arr1 after copying and changing an element in arr2: [10, 20, 30]
Deep Copy an Array Using the Arrays.copyOf Command in Java
Below, we use the copyOf() method of the Arrays utility class. It accepts the array to copy and its size then returns the array of the same type. We make a new array arr2 using this method and check if changing arr2 changes arr1 or not. The output shows the result.
Note that this method and the previous one create a shallow copy instead of a deep copy when the array contains objects instead of primitives.
import java.util.Arrays; public class DeepCopy public static void main(String[] args) int[] arr1 = 10, 20, 30>; System.out.println("arr1 Before copying: "+Arrays.toString(arr1)); int[] arr2 = Arrays.copyOf(arr1, arr1.length); System.out.println("arr2 After copying: "+Arrays.toString(arr1)); arr2[0] = 30; System.out.println("arr1 after copying and changing an element in arr2: "+Arrays.toString(arr1)); > >
arr1 Before copying: [10, 20, 30] arr2 After copying: [10, 20, 30] arr1 after copying and changing an element in arr2: [30, 20, 30]
We can also use Arrays.copyOf() to copy two dimensional array. In the example below, we have a 2D array arr . We have a new array arr2 , and in the loop, we use Arrays.copyOf that takes every element of arr and copies it into the arr2 item by item. Once copied, we check if arr1 changes if arr2 is changed. If it doesn’t change, it’s a deep copied array.
import java.util.Arrays; public class DeepCopy public static void main(String[] args) int[][] arr = <1, 2>, 3, 4>, 5, 6>>; System.out.println("Values of arr"); for (int i = 0; i arr.length; i++) for (int j = 0; j arr.length - 1; j++) System.out.println("arr[" + i + "][" + j + "] = " + arr[i][j]); System.out.println(); int[][] arr2 = new int[arr.length][]; for (int i = 0; i arr.length; i++) arr2[i] = Arrays.copyOf(arr[i], arr[i].length); > System.out.println("Values of arr2"); for (int i = 0; i arr2.length; i++) for (int j = 0; j arr2.length - 1; j++) System.out.println("arr2[" + i + "][" + j + "] = " + arr2[i][j]); arr2[0][1] = 5; System.out.println(); System.out.println("Values of arr after changing an element in arr2"); for (int i = 0; i arr.length; i++) for (int j = 0; j arr.length - 1; j++) System.out.println("arr[" + i + "][" + j + "] = " + arr[i][j]); > >
Values of arr arr[0][0] = 1 arr[0][1] = 2 arr[1][0] = 3 arr[1][1] = 4 arr[2][0] = 5 arr[2][1] = 6 Values of arr2 arr2[0][0] = 1 arr2[0][1] = 2 arr2[1][0] = 3 arr2[1][1] = 4 arr2[2][0] = 5 arr2[2][1] = 6 Values of arr after changing an element in arr2 arr[0][0] = 1 arr[0][1] = 2 arr[1][0] = 3 arr[1][1] = 4 arr[2][0] = 5 arr[2][1] = 6
Rupam Saini is an android developer, who also works sometimes as a web developer., He likes to read books and write about various things.