Как работает метод clone в Java
Что проверяют
Понимаете ли вы, почему механизм clone() считается неудачным и чем его заменяют на практике. Следом почти всегда спрашивают разницу между поверхностной и глубокой копией и как скопировать объект с изменяемыми полями.
Как отвечать
Механика в четырёх пунктах:
Object.clone(): объявленprotected native. Создаёт объект того же класса и копирует поля один в один, конструктор при этом не вызывается;Cloneable: маркерный интерфейс без методов. Он лишь меняет поведениеObject.clone(): без него метод бросает проверяемоеCloneNotSupportedException;- переопределение: в классе делают публичный метод с ковариантным типом возврата,
public Person clone(), внутриsuper.clone()и приведение. Раз класс реализуетCloneable, исключение ловят внутри и не выносят вthrows; - глубина: копия поверхностная. Примитивы и ссылки на неизменяемые объекты вроде
Stringглубже копировать не нужно, а изменяемые поля (массивы, коллекции,Date) клонируют вручную, иначе оригинал и копия делят одно состояние.
Дальше скажите, почему механизм не любят. Поле final нельзя переприсвоить после super.clone(), поэтому глубокую копию с ним не написать. Каждый класс в иерархии обязан корректно переопределить clone(), а контракт метода сформулирован слабо. Массивы клонируются удобно: int[] copy = arr.clone(); работает без приведения, но для массива объектов копия тоже поверхностная.
В современном коде предпочитают конструктор копирования new Person(other) или статическую фабрику Person.copyOf(other). Для неизменяемых данных есть record, их копировать не нужно вовсе. Копия через сериализацию медленная и требует Serializable у всего графа.
Где спотыкаются
Думают, что clone() вызывает конструктор. Он его обходит, поэтому проверки и логика конструктора на копии не выполняются.
Возвращают super.clone() для класса со списком внутри и считают копию независимой. ArrayList.clone() тоже поверхностный, элементы останутся общими.
Путают, где объявлен clone(), и говорят, что в Cloneable. В интерфейсе методов нет, метод живёт в Object, и именно поэтому без переопределения его нельзя вызвать извне.