Я искал несколько руководств по Java Cloneable
, но не получил хороших ссылок, и Stack Overflow в любом случае становится более очевидным выбором.
Я хотел бы знать следующее:
Cloneable
означает, что мы можем иметь клон или копию объектов, реализовавCloneable
интерфейс. Каковы преимущества и недостатки этого?- Как происходит рекурсивное клонирование, если объект является составным объектом?
Ответы:
Первое, о чем вы должны знать,
Cloneable
- не используйте его.Cloneable
Правильно осуществить клонирование очень сложно , да и усилия того не стоят.Вместо этого используйте другие параметры, например apache-commons
SerializationUtils
(deep-clone) илиBeanUtils
(shallow-clone), или просто используйте конструктор копирования.Посмотрите здесь мнение Джоша Блоха о клонировании с помощью
Cloneable
, которое объясняет многие недостатки этого подхода. ( Джошуа Блох был сотрудником Sun и руководил разработкой множества функций Java.)источник
static
методы в интерфейсах, поэтому просто укажитеstatic WhatEverTheInterface copy(WhatEverTheInterface initial)
? но мне интересно, что это дает вам, поскольку вы копируете поля из объекта во время клонирования, но интерфейс определяет только методы. хотите объяснить?Сам Cloneable, к сожалению, всего лишь интерфейс-маркер, то есть он не определяет метод clone ().
Что происходит, так это изменение поведения защищенного метода Object.clone (), который вызывает исключение CloneNotSupportedException для классов, которые не реализуют Cloneable, и выполняет поэлементное неглубокое копирование для классов, которые это делают.
Даже если это именно то поведение, которое вы ищете, вам все равно потребуется реализовать собственный метод clone (), чтобы сделать его общедоступным.
При реализации вашего собственного clone () идея состоит в том, чтобы начать с объекта, созданного с помощью super.clone (), который гарантированно относится к правильному классу, а затем выполнить любое дополнительное заполнение полей в случае, если неглубокая копия - это не то, что вы хотите. Вызов конструктора из clone () был бы проблематичным, поскольку это нарушило бы наследование, если подкласс хочет добавить свою собственную дополнительную клонируемую логику; если бы он вызвал super.clone (), в этом случае он бы получил объект неправильного класса.
Этот подход обходит любую логику, которая может быть определена в ваших конструкторах, что потенциально может быть проблематичным.
Другая проблема заключается в том, что любые подклассы, которые забывают переопределить clone (), автоматически наследуют мелкую копию по умолчанию, что, вероятно, не то, что вы хотите в случае изменяемого состояния (которое теперь будет совместно использоваться между источником и копией).
Большинство разработчиков не используют Cloneable по этим причинам, а просто реализуют вместо этого конструктор копирования.
Для получения дополнительной информации и потенциальных ошибок Cloneable я настоятельно рекомендую книгу Джошуа Блоха «Эффективная Java».
источник
Итак, используйте Cloneable разумно. Это не дает вам достаточных преимуществ по сравнению с усилиями, которые вам нужно приложить, чтобы все делать правильно.
источник
Клонирование - это базовая парадигма программирования. Тот факт, что Java, возможно, плохо реализовал это во многих отношениях, нисколько не уменьшает необходимость клонирования. И легко реализовать клонирование, которое будет работать так, как вы хотите, мелкое, глубокое, смешанное, что угодно. Вы даже можете использовать имя clone для функции и не реализовывать Cloneable, если хотите.
Предположим, у меня есть классы A, B и C, где B и C являются производными от A. Если у меня есть список объектов типа A, например:
Теперь этот список может содержать объекты типа A, B или C. Вы не знаете, к какому типу относятся эти объекты. Итак, вы не можете скопировать список так:
Если объект действительно относится к типу B или C, вы не получите нужную копию. А что, если А абстрактно? Некоторые люди предположили следующее:
Это очень и очень плохая идея. Что, если вы добавите новый производный тип? Что делать, если B или C находятся в другом пакете, и у вас нет доступа к ним в этом классе?
Вы бы хотели сделать следующее:
Многие люди указали, почему базовая реализация клона в Java является проблематичной. Но это легко преодолеть таким образом:
В классе А:
В классе B:
В классе C:
Я не использую Cloneable, просто использую то же имя функции. Если вам это не нравится, назовите что-нибудь другое.
источник
A) У клонирования не так много преимуществ перед конструктором копирования. Вероятно, самая большая из них - это возможность создать новый объект точно такого же динамического типа (при условии, что объявленный тип является клонируемым и имеет общедоступный метод клонирования).
B) Клон по умолчанию создает неглубокую копию, и она останется неглубокой копией, если ваша реализация клона не изменит ее. Это может быть сложно, особенно если в вашем классе есть поля final
Божо прав, клон бывает сложно получить правильно. Конструктор / фабрика копирования удовлетворит большинство потребностей.
источник
Какие недостатки у Cloneable?
Клонирование очень опасно, если объект, который вы копируете, имеет композицию. В этом случае вам нужно подумать о возможном побочном эффекте, поскольку клон создает неглубокую копию:
Допустим, у вас есть один объект для обработки манипуляций, связанных с БД. Скажем, у этого объекта есть
Connection
объект как одно из свойств.Поэтому , когда кто - то создает клон
originalObject
, объект создается, скажем,cloneObject
. ЗдесьoriginalObject
иcloneObject
содержится такая же ссылка наConnection
объект.Допустим,
originalObject
закрываетConnection
объект, так что теперьcloneObject
он не будет работать, потому чтоconnection
объект был разделен между ними, и он был фактически закрытoriginalObject
.Аналогичная проблема может возникнуть, если, скажем, вы хотите клонировать объект, имеющий IOStream в качестве свойства.
Как происходит рекурсивное клонирование, если объект является составным объектом?
Cloneable выполняет мелкое копирование. Это означает, что данные исходного объекта и объекта клона будут указывать на одну и ту же ссылку / память. Напротив, в случае глубокой копии данные из памяти исходного объекта копируются в память клонированного объекта.
источник
Cloneable
не выполняет копию,Object.clone
делает. «Данные из памяти исходного объекта копируются в память объекта-клона» - вот чтоObject.clone
делает. Чтобы описать глубокое копирование, нужно говорить о памяти объектов, на которые имеются ссылки.