-
Notifications
You must be signed in to change notification settings - Fork 3
How about Clone?
Иногда мы работаем с неизменяемыми объектами, тогда, при работе с таким объектом часто бывает полезно создать его копию и работать с ней. Также часто бывает создать копию какого-либо объекта и работать с ней, при этом не изменяя первоначальный объект.
Одним из способов клонировать объект является переопределение метода clone() и реализация интерфейса Cloneable();.
У объекта Object есть метод clone, как он объявлен?
protected Object clone() throws CloneNotSupportedExceptionПо умолчанию этот метод определяет 'поверхностное' копирование, копируются значения всех полей и ссылок. Так как он protected, то у объектов, не переопределивших его, этот метод не получится вызвать.
Заметим также, что с версии 1.5 хорошим тоном при переопределении этого метода является явное указание возвращаемого объекта, а не Object.
В java есть интерфейс-маркер Cloneable, который показывает, может ли объект быть клонирован. Классы, открывающие метод clone обязаны реализовывать этот интерфейс.
Сам Object - это не реализует этот интерфейс.
Почему? Потому, что не всем классам это надо. Не все классы обязательно должны уметь клонироваться. А реализовав интерфейс в Object мы бы потащили его везде.
Однако, как мы помним, если поля класса содержат ссылки на изменяемые объекты, то при клонировании будет скопирована именно ссылка, а значит, изменив такое поле в клоне объекта - мы измени его и в оригинальном!
А это может иметь печальные последствия.
Избежать можно вот как: воспользоваться конструктором копирования.
Т.е сначала вызвать clone супер класса, а после уже работать с такими опасными полями.
Отметим, что клонирование таким способом НЕ работает, если поле помечено как final.
Все методы, реализующие Cloneable должны переопределять clone и делать его открытым. В переопределенном методе необходимо сначала вызвать super.clone(), после чего начать работать с полями, значения которых могут изменяться, т.е надо заменять все ссылки на объекты соответствующими копиями.
Лучшим вариантом является определение конструктора-копий или статический метод генерации.
Плюсы таких вариантов заключается в том, что это проще, клиент получает объект определенного типа, не отлавливает исключения, можно работать с final полями.
Этот вариант является гораздо более предпочтительным.