Пример Java ArrayList clone() и глубокого копирования

В Java метод ArrayList clone() создает поверхностную копию списка, в которой копируются только ссылки на объекты. Если мы изменим состояние объекта элемента списка внутри первого ArrayList, измененное состояние объекта также будет отражено в клонированном списке.

Чтобы предотвратить отражение изменений в обоих списках, нам следует явно создать глубокую копию списка.

1. Использование ArrayList.clone() для поверхностного копирования

Метод clone() создает новый ArrayList, а затем копирует резервный массив в клонированный массив. Он создает поверхностную копию заданного arraylist. В поверхностной копии исходный список и клонированный список ссылаются на одни и те же объекты в памяти.

Давайте рассмотрим внутреннюю реализацию метода клонирования.

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 Cloneablethrow new InternalError(e);}}

Следующая программа Java создает поверхностную копию ArrayList с помощью метода clone().

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

2. Создание глубокой копии ArrayList

Создание глубокой копии списка — непростая задача. Java не поддерживает глубокое копирование по умолчанию. Поэтому нам придется вручную изменить код, чтобы включить глубокое копирование классов и коллекций. В глубокой копии списка элементы, на которые ссылаются оба списка, являются разными экземплярами в памяти.

Глубокое копирование ArrayList

3.1. Включить глубокое копирование для элемента списка

Чтобы создать глубокую копию любого класса, разделите все члены класса на две категории: изменяемые и неизменяемые типы.

  • Все неизменяемые члены поля могут использоваться как есть. Они не требуют какой-либо специальной обработки. Например, примитивные классы, классы-обертки и класс String.
  • Для всех изменяемых полей-членов мы должны создать новый объект-член и присвоить его значение клонированному объекту.

Идея состоит в том, чтобы вернуть неизменяемую копию класса из метода clone(). Проверьте переопределенный метод clone() в следующем классе:

public class Employee implements Cloneable {private Long id;private String name;private Date dob; //Mutable fieldpublic Employee(Long id, String name, Date dob) {super();this.id = id;this.name = name;this.dob = dob;}//Getters and setters@Overrideprotected Object clone() throws CloneNotSupportedException {Employee clone = null;try {clone =(Employee) super.clone();//Copy new date object to cloned methodclone.setDob((Date) this.getDob().clone());}catch(CloneNotSupportedException e) {throw new RuntimeException(e);}return clone;}@Overridepublic String toString() {return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]";}}

3.2 Глубокое копирование коллекций Java

Создание глубокой копии коллекции довольно просто. Нам нужно создать новый экземпляр коллекции и скопировать все элементы из данной коллекции в клонированную коллекцию – один за другим. Обратите внимание, что мы скопируем клон элемента в клонированную коллекцию.

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

3.3.Демо

Программа Java для создания глубокой копии 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 itememployeeListClone.get(0).setId(2l);employeeListClone.get(0).setName("brian");employeeListClone.get(0).getDob().setDate(13);;System.out.println(employeeList);System.out.println(employeeListClone);

Вывод программы. Обратите внимание, что даже после изменения значений объекта Employee в employeeListClone исходный список сотрудников employeeList не изменяется.

[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]]
Прокрутить вверх