Почему метод clone() защищен в java.lang.Object?

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

11 ответов

Решение

Тот факт, что клон защищен, чрезвычайно сомнителен, как и тот факт, что 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 был задуман как смешанный интерфейс для объектов, объявляющих о том, что они разрешают клонирование. К сожалению, он не подходит для этой цели... Это очень нетипичное использование интерфейсов, а не тот, который нужно эмулировать... Для реализации интерфейс, чтобы иметь какое-либо влияние на класс, он и все его суперклассы должны подчиняться довольно сложному, неисполнимому и в значительной степени недокументированному протоколу"

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

От солнца:

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

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

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

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

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

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

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

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

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

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

Это protected,

Реализация классов 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 или нет". Именно так, как думала команда 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 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-класса.

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