Защитные копии Java

Я видел защитные копии, закодированные так

void someMethod(Date d) {
    myDate = new Date( d.getTime() );
}

Но это не имеет смысла для меня, разве в Java нет способа создать идентичную копию в памяти этого объекта?

Я прочитал clone() не будет работать во всех случаях, но я не понимаю, почему.

4 ответа

Я мог бы попытаться ответить на это, но я бы просто занялся плагиатом Джоша Блоха, так что вместо этого вот ссылка на ресурс:

Копировать конструктор против клонирования

Билл Веннерс: в своей книге вы рекомендуете использовать конструктор копирования вместо реализации Cloneable и писать clone , Не могли бы вы уточнить это?

Джош Блох: Если вы читали статью о клонировании в моей книге, особенно если вы читаете между строк, вы поймете, что я думаю, что клон глубоко сломан. Есть несколько недостатков дизайна, самый большой из которых заключается в том, что Cloneable Интерфейс не имеет clone метод. А это значит, что это просто не работает: сделать что-то Cloneable ничего не говорит о том, что вы можете сделать с этим. Вместо этого он говорит что-то о том, что он может сделать внутри. Он говорит, что если по телефону super.clone неоднократно это заканчивает тем, что звонило Object "s clone метод, этот метод будет возвращать копию поля оригинала.

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

Дело в том, что вы не предоставляете своим клиентам никаких возможностей, внедряя Cloneable и предоставление общественности clone метод, кроме способности копировать. Это не лучше, чем вы получаете, если вы предоставляете операцию копирования с другим именем и не реализуете Cloneable, Это в основном то, что вы делаете с конструктором копирования. Подход конструктора копирования имеет несколько преимуществ, которые я обсуждаю в книге. Одним из больших преимуществ является то, что копия может быть сделана так, чтобы иметь представление, отличное от оригинала. Например, вы можете скопировать LinkedList в ArrayList,

Object "s clone метод очень хитрый. Он основан на полевых копиях и является "внеязыковым". Он создает объект без вызова конструктора. Нет никаких гарантий, что он сохранит инварианты, установленные конструкторами. За эти годы было много ошибок, как внутри, так и за пределами Sun, что связано с тем, что если вы просто позвоните super.clone несколько раз вверх по цепочке, пока вы не клонируете объект, у вас есть мелкая копия объекта. Клон обычно разделяет состояние с клонируемым объектом. Если это состояние изменчиво, у вас нет двух независимых объектов. Если вы измените один, другой тоже изменится. И вдруг, вы получаете случайное поведение.

Есть очень мало вещей, для которых я использую Cloneable больше. Я часто предоставляю публике clone метод на конкретных классах, потому что люди ожидают этого. У меня нет абстрактных классов реализовать Cloneable и у меня нет интерфейсов, расширяющих его, потому что я не возьму на себя бремя реализации Cloneable на всех классах, которые расширяют (или реализуют) абстрактный класс (или интерфейс). Это настоящее бремя, с небольшими преимуществами.

Даг Ли идет еще дальше. Он сказал мне, что он не использует clone больше, кроме как для копирования массивов. Вы должны использовать clone копировать массивы, потому что это, как правило, самый быстрый способ сделать это. Но типы Дуга просто не реализуют Cloneable больше. Он разочаровался в этом. И я думаю, что это не лишено смысла.

Обидно что Cloneable сломан, но это случается. Оригинальные API Java были сделаны очень быстро в сжатые сроки, чтобы соответствовать закрывающемуся окну рынка. Оригинальная команда Java проделала невероятную работу, но не все API идеальны. Cloneable это слабое место, и я думаю, что люди должны знать о его ограничениях.

clone() реализуется осмысленно только в некоторых классах, потому что существует множество решений, связанных с клонированием, которые JVM или компилятор не принимает за вас (например, мелкое копирование или глубокое копирование). Некоторые также утверждают, что вся концепция Java нарушена и поэтому используется редко.

Конечным результатом, однако, является то, что многие классы не могут быть клонированы. В этих случаях пользователь клонирует их, генерируя и инициализируя один объект на основе другого.

Тем не менее Date реализует класс Cloneableтак что в данном конкретном случае нет никакой пользы от использования "конструктора копирования".

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

Допустим, в данном случае это плюс. Вы бы назвали clone ссылкой на Expression, но на самом деле вы получите новый экземпляр Plus. С конструкторами вы не можете этого сделать, потому что ваше выражение может быть интерфейсом или абстрактным классом.

Нет простого способа сделать идентичную копию, которая всегда работает.

Клон должен был это сделать, но он реализован не всеми классами и, таким образом, более или менее нарушен.

Другой подход заключается в сериализации / десериализации, но сериализация также поддерживается не всеми классами.

С точки зрения безопасности мобильного кода, clone обычно может быть переопределено.

@Override public Date clone() {
    return this; // Ha!
}

Даже если вы не заботитесь о безопасности, вы можете представить, что программист "умный", вызывая сообщение об ошибке в вашем коде.

Ожидание, что особенно clone вернет точно такой же тип во время выполнения и вызовет проблемы с реализацией.

Другие вопросы по тегам