Почему метод Object clone () доступен только классам, реализующим клонируемый интерфейс? [дубликат]

этот вопрос уже есть ответ здесь:

Я знаю, что clone() является защищенным методом, но "защищенный" означает, что он доступен для всех подклассов определенного класса.

любой класс Java является подклассом Object, так в чем причина защищенного метода?

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

6 ответов


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

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

в качестве дополнительной проверки, clone проверяет, что класс реализует Cloneable, только чтобы убедиться, что вы не клон не cloneables случайно.


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

public class Base {

    /** one or more public constructors */
    public Base() { ... }

    /** copy-constructor */
    protected Base(Base src) { /* copy or deep-copy the state */ }

    public Base copy() { return new Base(this); }
}

public class Derived extends Base {

    /** one or more public constructors */
    public Derived() { ... }

    /** copy-constructor */
    protected Derived(Derived src) { 
        super(src);
        /* copy or deep-copy the state */ 
    }

    @Override
    public Derived copy() { return new Derived(this); }
}

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

оглядываясь назад, правильнее было бы определить систему CloneableObject, который наследует от Object который включает в себя защищенный memberwiseclone метод (который работает как Object.clone() теперь) и ничего больше, и все классы, которые будут клонироваться, наследуются от этого как их базовый тип. Этот тип мог бы использовать тогда какую-то особую магию в своем clone() метод, который был недоступен для других типов. Вместо этого, однако, система использует существование the Cloneable интерфейс, чтобы решить, следует ли разрешать объектам использовать базовый уровень clone() метод. Не очень хороший дизайн, но это то, что есть. Трудно сказать, лучше ли это или хуже, чем подход .NET, позволяющий почти всем производным классам вызывать MemberwiseClone будет ли какой-либо способ производного класса сделать это, не давая сломанного объекта.


потому что так они его спроектировали. Где-то в параде ошибок есть утверждение, что первоначальные причины дизайна "потеряны в тумане времени", но я помню дискуссию Sun в 1990-х годах, в которой говорилось, что дизайн дал четыре возможных поведения.

не могу вспомнить детали : - / но вы можете разобраться:

  1. ничего не делать. Класс нельзя клонировать и clone() метод недоступен, кроме производного занятия.
  2. реализовать Cloneable: класс можно клонировать, но clone() способ недоступен, за исключением производных классов.
  3. реализовать Cloneable и обеспечить свой собственный clone() способ: как (2), но существует возможность сделать clone() public, а также теперь, чтобы вернуть правильный тип.
  4. производный от класса, который делает (2) или (3), реализует clone(), и бросить NotCloneableException: вы вернулись к 1.

положить clone() в интерфейс бы потеряли немного.


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

пожалуйста, обратитесь к:


http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html

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

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

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

идешь в свой вопрос, даже если объект имеет защищенный метод clone Object не реализует Cloneable,но объект называется clone() метод должен реализовать Cloneable interface.


Cloneable является маркер интерфейс. Метод clone () не определяется интерфейсом Cloneable.

метод clone в классе Object защищен, чтобы предотвратить вызов клиентского класса - только подклассы могут вызывать или переопределять clone, и это плохая идея.