Копирование и clone()
У слова «копия» нет единственной семантики. Сначала нужно решить, делятся ли вложенные объекты между экземплярами.
| Копия | Что происходит с полями-ссылками |
|---|---|
| shallow | ссылки копируются, вложенные объекты общие |
| deep | нужный граф объектов копируется рекурсивно |
Механизм Object.clone
Cloneable — маркерный интерфейс без метода clone. Защищённый Object.clone() делает поразрядную shallow-копию полей и бросает CloneNotSupportedException, если класс не реализует Cloneable. Конструкторы при этом не вызываются.
final class Draft {
private final String title;
private final List<String> lines;
Draft(String title, List<String> lines) {
this.title = title;
this.lines = new ArrayList<>(lines);
}
Draft(Draft source) { // явный copy constructor
this(source.title, source.lines);
}
}В прикладном коде copy constructor или именованная фабрика обычно лучше clone: виден контракт, можно проверить инварианты и выбрать глубину копии.
Draft copy = new Draft(original);Массивы имеют публичный clone() и копируют структуру массива, но элементы ссылочного массива остаются общими. Неизменяемые объекты копировать обычно не нужно.
Почему сериализация — плохой универсальный clone
Она медленнее, требует сериализуемости всего графа, связывает копирование с форматом и может выполнять небезопасную десериализацию. JSON round-trip также меняет типы/идентичность и скрывает контракт.
Ошибки
- назвать копию deep, скопировав только список, но не его изменяемые элементы;
- использовать
clone()в наследуемом классе без продуманного контракта; - забыть про циклы и общие ссылки внутри графа;
- копировать entity ORM и случайно переносить идентификатор/служебное состояние.
На собеседовании
Что делает Object.clone()? Shallow-копию полей без вызова конструктора.
Зачем Cloneable, если в нём нет методов? Это разрешающий маркер для Object.clone().
Копирует ли ArrayList.clone() элементы? Нет, копируется структура списка и ссылки на элементы.
Что предпочесть в доменной модели? Явный copy constructor/фабрику с описанной семантикой.
Связано: Сериализация и клонирование, Immutable классы и данные.