ПрограммированиеJava разработчик

Объясните разницу между shallow copy и deep copy объектов в Java. Как их можно реализовать, и в каких ситуациях важно понимать эту разницу?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

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

Пример shallow copy (через clone)

class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } // Использование Person p1 = new Person("Ivan", new Address("Moscow")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburg"; System.out.println(p1.address.city); // Выведет "Petersburg" — поверхностное копирование

Пример deep copy

class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return new Address(this.city); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = (Address) address.clone(); return cloned; } }

Глубокое копирование позволяет создать полностью независимую копию объекта.

Вопрос с подвохом.

Вопрос: Можно ли использовать метод clone() для гарантированного глубокого копирования произвольного сложного объекта?

Ответ: Нет, стандартный clone() делает только поверхностное копирование (shallow copy). Для глубокого копирования необходимо переопределять clone() во всех вложенных классах и явно клонировать все поля-ссылки. Также многие коллекции и стандартные классы не поддерживают глубокое клонирование.

Примеры реальных ошибок из-за незнания тонкостей темы.


История

Коллекция пользователей и их адресов клонировалась методом clone() без глубокого копирования. После изменения адреса у одного пользователя изменился адрес и у другого, потому что копировалась ссылка. Данные в базе "потекли" между пользователями.


История

При сериализации сложного объекта с вложенными коллекциями использовали clone(), а не глубокую копию. После восстановления из сериализации данные оказались неконсистентными и произошли NPE.


История

В REST API DTO-объекты клонировались по умолчанию через BeanUtils.copyProperties(), что приводило к разделению одной и той же коллекции между клиентами. В результате пользователь мог видеть и редактировать чужие данные.