Почему люди так боятся использовать clone () (на коллекциях и JDK-классах)? - PullRequest
41 голосов
/ 08 апреля 2010

Несколько раз я утверждал, что использование clone() не такая уж плохая практика. Да, я знаю аргументы. Блох сказал это плохо. Он действительно сделал, но он сказал, что реализация clone() это плохо. С другой стороны, использовать клон, особенно если он правильно реализован доверенной библиотекой, такой как JDK, вполне нормально.

Буквально вчера у меня была дискуссия о моем ответе , который просто предполагает, что использование clone() для ArrayList - это нормально (и я думаю, что по этой причине я не получил никаких голосов).

Если мы посмотрим на @author из ArrayList, мы увидим знакомое имя - Джош Блох. Так что clone() на ArrayList (и других коллекциях) прекрасно (смотрите только их реализации).

То же самое касается Calendar и, возможно, большинства классов java.lang и java.util.

Итак, дайте мне причину почему бы не использовать clone() с классами JDK?

Ответы [ 7 ]

22 голосов
/ 08 апреля 2010

Итак, дайте мне причину, почему бы не использовать clone () с классами JDK?

  • Учитывая ссылку ArrayList, вам потребуется проверка getClass, чтобы убедиться, что она не является подклассом класса JDK. И что потом? Потенциальным подклассам нельзя доверять. Предположительно, подкласс будет иметь другое поведение в некотором роде.
  • Требуется, чтобы ссылка была более конкретной, чем List. Некоторые люди не возражают против этого, но большинство считает, что это плохая идея.
  • Вам придется иметь дело с гипсом, небезопасным при этом.
9 голосов
/ 08 апреля 2010

Исходя из моего опыта, проблема clone () возникает на производных классах.

Скажем, ArrayList реализует clone (), который возвращает объект ArrayList.

Предположим, ArrayList имеет производный класс, а именно MyArrayList. Будет катастрофой, если MyArrayList не переопределит метод clone (). (По умолчанию он наследует код от ArrayList).

Пользователь MyArrayList может ожидать, что clone () вернет объект MyArrayList; Однако это не так.

Это раздражает: если базовый класс реализует clone (), его производный класс должен полностью переопределить clone ().

7 голосов
/ 08 апреля 2010

Я отвечу цитатой из самого человека ( Джош Блох о дизайне - конструктор копирования против клонирования ):

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

Это не может быть более явным, чем это: clone() в его коллекциях Framework Framework предоставляются , потому что люди ожидают этого . Если бы люди перестали этого ожидать, он бы с радостью выбросил это. Один из способов заставить людей перестать ожидать его - научить людей не использовать его, а не пропагандировать его использование.

Конечно, сам Блох также говорил (не точная цитата, но близко): «API - это как секс: совершите одну ошибку, и вы поддержите ее на всю жизнь». Любой public clone(), вероятно, никогда не сможет быть возвращен. Тем не менее, это недостаточно веская причина для его использования.

6 голосов
/ 08 апреля 2010

Чтобы не поощрять других, менее опытных разработчиков внедрять Clone() самим.Я работал со многими разработчиками, чьи стили кодирования в основном скопированы из (иногда ужасного) кода, с которым они работали.

3 голосов
/ 08 апреля 2010

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

1 голос
/ 08 апреля 2010

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

В большом приложении, большой команде, это также рискованно, потому что при использовании клонирования, если вы изменяете реализацию клона, вы можете изменить поведение приложения и создавать новые ошибки ... и должны проверять везде, где был вызван клон (но это может быть то же самое для других методов объекта, таких как equals, toString ...

Если при модификации клона небольшого подкласса A (от глубокого к мелкому клону для примера), если экземпляр B имеет ссылку на A и подразумевается глубокий клон, то, поскольку объекты, на которые есть ссылки в A, не являются мелкими клонированными, клон B больше не будет глубоким клоном (и то же самое для любого класса, ссылающегося на экземпляр B ...). Нелегко иметь дело с глубиной ваших методов клонирования.

Также, когда у вас есть интерфейс (расширяющий Clonable) и многие (многие!) Реализации, иногда вы проверяете некоторые значения и видите, что клоны глубоки, и вызываете клон на интерфейсе, но вы не можете быть уверены во время выполнения Все Impl действительно имеют глубокий клон и могут вносить ошибки ...

Подумайте, что может быть лучше для каждого метода включить метод shallowClone и метод deepClone, а для очень специфических нужд внедрить настраиваемые методы (например, вы хотите клонировать и ограничить глубину этого клона до 2, сделайте пользовательский импл для что во всех соответствующих классах).

Не думайте, что важно использовать метод клонирования в классе JDK, поскольку он не будет изменен другим разработчиком или, по крайней мере, не часто. Но вам лучше не вызывать clone для классов JDK, если вы не знаете реализацию класса во время компиляции. Я имею в виду, что вызов клона в ArrayList не имеет значения, но вызов его в Collection может быть опасным, поскольку другая реализация Collection может быть введена другим разработчиком (он может даже расширить коллекцию impl), и ничто не говорит вам, что клон этого impl будет работать так, как вы ожидаете ...

0 голосов
/ 08 апреля 2010

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

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