Какая конкретная причина clone()
определяется как защищенная в java.lang.Object
?
Какая конкретная причина clone()
определяется как защищенная в java.lang.Object
?
Ответы:
Тот факт, что clone защищен, крайне сомнительный, как и тот факт, что 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 был задуман как интерфейс примеси для объектов, чтобы объявлять о том, что они разрешают клонирование. К сожалению, он не служит этой цели ... Это очень нетипичное использование интерфейсов, и его нельзя эмулировать. ... Чтобы реализация интерфейса оказывала какое-либо влияние на класс, он и все его суперклассы должны подчиняться довольно сложному, не имеющему законной силы и в значительной степени недокументированному протоколу "
Serializable
- решать, реализовывать ли его, зависит от реализации Serializable
. Я расширял это Cloneable
- это не то, что должен расширять интерфейс, - но реализация интерфейса может быть свободной Cloneable
. Проблема в том, что если у вас есть параметр типа интерфейса, вы спрашиваете его, можно ли его клонировать; но тогда вы не сможете его клонировать!
Интерфейс Clonable - это просто маркер, говорящий, что класс может поддерживать клонирование. Метод защищен, потому что вы не должны вызывать его для объекта, вы можете (и должны) переопределить его как общедоступный.
От вс:
В классе Object метод clone () объявлен защищенным. Если все, что вы делаете, это реализуете Cloneable, только подклассы и члены одного пакета смогут вызывать clone () для объекта. Чтобы разрешить любому классу в любом пакете обращаться к методу clone (), вам придется переопределить его и объявить общедоступным, как это делается ниже. (Когда вы переопределяете метод, вы можете сделать его менее частным, но не более частным. Здесь защищенный метод clone () в Object переопределяется как открытый метод.)
Set
clone
защищен, потому что это то, что нужно переопределить, чтобы оно было специфичным для текущего класса. Хотя можно было бы создать общедоступный clone
метод, который вообще клонировал бы любой объект, это было бы не так хорошо, как метод, написанный специально для класса, который в нем нуждается.
Метод Clone нельзя напрямую использовать ни с одним объектом, поэтому он предназначен для переопределения подклассом.
Конечно, он может быть публичным и просто генерировать соответствующее исключение, когда клонирование невозможно, но я думаю, что это будет вводить в заблуждение.
То, как сейчас реализовано клонирование, заставляет задуматься о том, почему вы хотите использовать клон и как вы хотите, чтобы ваш объект был клонирован.
Он защищен, потому что реализация по умолчанию делает мелкую поэлементную копию всех полей (включая частные), обходя конструктор . Это не то, что объект может быть разработан для обработки в первую очередь (например, он может отслеживать созданные экземпляры объекта в общем списке или что-то подобное).
По той же причине реализация по умолчанию clone()
выбросит, если объект, который она вызывает, не реализует Cloneable
. Это потенциально небезопасная операция с далеко идущими последствиями, и поэтому автор класса должен явным образом согласиться.
Из javadoc cloneable.
* 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.
Таким образом, вы можете вызвать clone для каждого объекта, но в большинстве случаев это даст вам не те результаты, которые вы хотите, или исключение. Но это приветствуется, только если вы реализуете cloneable.
ИМХО это так просто:
#clone
не должен вызываться для неклонируемых объектов, поэтому он не публикуется#clone
должен вызываться подклассами ob, Object
которые реализуют Cloneable, чтобы получить неглубокую копию правильного классаКакова правильная область действия методов, которые должны вызываться подклассами, но не другими классами?
Это protected
.
Реализация классов, Cloneable
конечно же, сделает этот метод общедоступным, чтобы его можно было вызывать из других классов.
Метод Clone () имеет внутреннюю проверку «экземпляр Cloneable или нет». Именно так группа разработчиков Java могла подумать, что ограничит неправильное использование метода clone (). Метод clone () защищен, т.е. доступен только для подклассов. Поскольку объект является родительским классом для всех подклассов, метод Clone () может использоваться всеми классами фактически, если у нас нет вышеуказанной проверки «экземпляра Cloneable». Это причина того, что команда Java могла подумать об ограничении ненадлежащего использования clone () с помощью проверки в методе clone () «это экземпляр Cloneable».
Следовательно, любые классы, реализующие cloneable, могут использовать метод clone () класса Object.
Кроме того, поскольку он сделан защищенным, он доступен только тем подклассам, которые реализуют клонируемый интерфейс. Если мы хотим сделать его общедоступным, этот метод должен быть переопределен подклассом с его собственной реализацией.
Да, та же проблема, что и я. Но я решаю это, реализуя этот код
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Как и раньше, кто-то сказал.
Что ж, разработчики sun - всего лишь люди, и они действительно совершили огромную ошибку, реализовав метод клонирования как защищенный, такую же ошибку, как они реализовали нефункционирующий метод клонирования в ArrayList! Так что в целом даже опытные программисты на Java имеют гораздо более глубокое непонимание метода клонирования.
Однако недавно я нашел быстрое и простое решение для копирования любого объекта со всем его содержимым, независимо от того, как он построен и что он содержит, см. Мой ответ здесь: Ошибка при использовании Object.clone ()
И снова фреймворк Java JDK демонстрирует блестящее мышление:
Клонируемый интерфейс не содержит «public T clone ()»; , потому что он действует больше как атрибут (например, Serializable), который позволяет клонировать экземпляр.
В этом дизайне нет ничего плохого, потому что:
Object.clone () не будет делать то, что вы хотите, с вашим пользовательским классом.
Если у вас есть Myclass, который реализует Cloneable =>, вы перезаписываете clone () с помощью «public MyClass clone ()»
Если у вас есть MyInterface extends Cloneable и некоторые MyClasses, реализующие MyInterface: просто определите «public MyInterface clone ();» в интерфейсе, и каждый метод, использующий объекты MyInterface, сможет их клонировать, независимо от их MyClass-класса.