Skip to content
Aleksandr Kuchuk edited this page Aug 2, 2016 · 3 revisions

Введение

Иногда мы работаем с неизменяемыми объектами, тогда, при работе с таким объектом часто бывает полезно создать его копию и работать с ней. Также часто бывает создать копию какого-либо объекта и работать с ней, при этом не изменяя первоначальный объект.

Одним из способов клонировать объект является переопределение метода clone() и реализация интерфейса Cloneable();.

Подробнее.

У объекта Object есть метод clone, как он объявлен?

protected Object clone() throws CloneNotSupportedException

По умолчанию этот метод определяет 'поверхностное' копирование, копируются значения всех полей и ссылок. Так как он protected, то у объектов, не переопределивших его, этот метод не получится вызвать. Заметим также, что с версии 1.5 хорошим тоном при переопределении этого метода является явное указание возвращаемого объекта, а не Object.

В java есть интерфейс-маркер Cloneable, который показывает, может ли объект быть клонирован. Классы, открывающие метод clone обязаны реализовывать этот интерфейс. Сам Object - это не реализует этот интерфейс. Почему? Потому, что не всем классам это надо. Не все классы обязательно должны уметь клонироваться. А реализовав интерфейс в Object мы бы потащили его везде.

Clone example

Однако, как мы помним, если поля класса содержат ссылки на изменяемые объекты, то при клонировании будет скопирована именно ссылка, а значит, изменив такое поле в клоне объекта - мы измени его и в оригинальном!

А это может иметь печальные последствия.

Example of wrong work

Как такого избежать?

Избежать можно вот как: воспользоваться конструктором копирования. Т.е сначала вызвать clone супер класса, а после уже работать с такими опасными полями.

Example of clone

Отметим, что клонирование таким способом НЕ работает, если поле помечено как final.

Что в итоге?

Все методы, реализующие Cloneable должны переопределять clone и делать его открытым. В переопределенном методе необходимо сначала вызвать super.clone(), после чего начать работать с полями, значения которых могут изменяться, т.е надо заменять все ссылки на объекты соответствующими копиями.

Лучшим вариантом является определение конструктора-копий или статический метод генерации. Плюсы таких вариантов заключается в том, что это проще, клиент получает объект определенного типа, не отлавливает исключения, можно работать с final полями.

Этот вариант является гораздо более предпочтительным.

Static method for clone

Clone this wiki locally