Почему метод clone () защищен в java.lang.Object? - PullRequest
102 голосов
/ 16 июля 2009

Какова конкретная причина, по которой clone() определяется как защищенный в java.lang.Object?

Ответы [ 11 ]

102 голосов
/ 16 июля 2009

Тот факт, что клон защищен, чрезвычайно сомнителен, как и тот факт, что метод clone не объявлен в интерфейсе Cloneable.

Это делает метод довольно бесполезным для получения копий данных, потому что вы не можете сказать :

if(a instanceof Cloneable) {
    copy = ((Cloneable) a).clone();
}

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

ISomething i = ...
if (i instanceof Cloneable) {
   //DAMN! I Need to know about ISomethingImpl! Unless...
   copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}

Цитата из Эффективная Java Джоша Блоха :
"Интерфейс Cloneable был задуман как смешанный интерфейс для объектов, объявляющих о том, что они разрешают клонирование. К сожалению, он не предназначен для этой цели ... Это очень нетипичное использование интерфейсов, а не тот, который нужно эмулировать ... Чтобы реализация интерфейса оказала какое-либо влияние на класс, он и все его суперклассы должны подчиняться довольно сложному, неисполнимому и в значительной степени недокументированному протоколу"

27 голосов
/ 16 июля 2009

Интерфейс Clonable - это просто маркер, говорящий, что класс может поддерживать клон. Метод защищен, потому что вы не должны вызывать его для объекта, вы можете (и должны) переопределить его как открытый.

От Солнца:

В классе Object метод clone () объявлен защищенным. Если все, что вы делаете, это реализуете Cloneable, только подклассы и члены одного и того же пакета смогут вызывать clone () для объекта. Чтобы разрешить любому классу в любом пакете доступ к методу clone (), вам придется переопределить его и объявить его общедоступным, как это сделано ниже. (Когда вы переопределяете метод, вы можете сделать его менее приватным, но не более закрытым. Здесь защищенный метод clone () в Object переопределяется как открытый метод.)

7 голосов
/ 16 июля 2009

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

4 голосов
/ 16 июля 2009

Метод Clone нельзя напрямую использовать с любым объектом, поэтому он предназначен для переопределения подклассом.

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

То, как клон реализован прямо сейчас, заставляет задуматься о том, почему вы хотите использовать клон и как вы хотите, чтобы ваш объект был клонирован.

2 голосов
/ 05 сентября 2016

ИМХО, все так просто:

  • #clone нельзя вызывать для не клонируемых объектов, поэтому оно не публикуется
  • #clone должен вызываться подклассами ob Object, которые реализуют Cloneable, чтобы получить мелкую копию нужного класса

Какова правильная область применения методов, которые должны вызываться подклассами, но не другими классами?

Это protected.

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

2 голосов
/ 16 июля 2009

Из javadoc клонируемого.

* By convention, classes that implement this interface (cloneable) should override 
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.

* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface.  Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.

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

2 голосов
/ 16 июля 2009

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

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

0 голосов
/ 18 августа 2018

Метод Clone () имеет внутреннюю проверку «экземпляр Cloneable или нет». Так, как думала команда Java, будет ограничено неправильное использование метода clone (). Метод clone () защищен, то есть доступен только подклассам. Поскольку объект является родительским классом для всех подклассов, метод Clone () может использоваться всеми классами, если у нас нет проверки «экземпляра Cloneable» выше. По этой причине команда Java могла подумать об ограничении ненадлежащего использования clone () с помощью проверки в методе clone () «это экземпляр Cloneable».

Следовательно, все классы, реализующие cloneable, могут использовать метод clone () класса Object.

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

0 голосов
/ 21 октября 2012

Ну, и разработчики Sun - всего лишь люди, и они действительно совершили огромную ошибку, чтобы реализовать метод клонирования как защищенный, ту же ошибку, что и они реализовали неработающий метод клонирования в ArrayList! Так что, в целом, даже более опытные Java-программисты имеют гораздо более глубокое недопонимание относительно метода клонирования.

Однако недавно я нашел быстрое и простое решение для копирования любого объекта со всем его содержимым, независимо от того, как он построен и что в нем содержится, см. Мой ответ здесь: Ошибка при использовании Object.clone ( )

0 голосов
/ 31 мая 2010

Опять же, Java JDK framework демонстрирует блестящее мышление:

Cloneable интерфейс не содержит "public T clone ();" метод, потому что он действует больше как атрибут (например, Serializable), который позволяет экземпляру его клонировать.

В этом дизайне нет ничего плохого, потому что:

  1. Object.clone () не будет делать то, что вы хотите с вашим пользовательским классом.

  2. Если у вас в Myclass реализован Cloneable =>, вы перезаписываете clone () с помощью "public MyClass clone ()"

  3. Если у вас MyInterface расширяет Cloneable и некоторые MyClasses реализуют MyInterface: просто определите "public MyInterface clone ();" в интерфейсе и каждый метод, использующий объекты MyInterface, сможет их клонировать, независимо от их класса MyClass.

...