Возвращаемая неопределенность типа - PullRequest
4 голосов
/ 28 августа 2011

Рассмотрим следующий код из книги «Язык программирования Java»

public class MyClass extends HerClass implements Cloneable {
   public MyClass clone()
       throws CloneNotSupportedException {
       return (MyClass) super.clone();
   }
   // ...
}

Когда функция overiding clone () уже определяет тип возвращаемого значения как MyClass, тогда каково требование его повторного указания в операторе возврата? Кроме того, поскольку создается клон объекта суперкласса Myclass (поскольку clone () вызывается вместо суперкласса), как он может иметь тип Myclass?

Заранее спасибо

Ответы [ 4 ]

1 голос
/ 28 августа 2011

Ваш простой вопрос: почему super.clone() приведен к MyClass? Это связано с тем, что объявление HerClass.clone() указывает возвращаемое значение HerClass, поэтому вы должны привести его к нужному типу.

Теперь по более сложному вопросу: как super.clone() может на самом деле вернуть экземпляр MyClass? На самом деле мне было трудно найти ответ, но я нашел какой-то ответ в «Эффективной Java» Джошуа Блоха. На фоне Object.clone() все еще есть какая-то "магия", которую я не совсем понимаю.

Пункт 11 из книги:

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

Изначально я пытался ответить на ваш вопрос, написав программу, не зная, что вам всегда приходилось звонить super.clone(). Мой самодельный метод клонирования для HerClass возвращал новый экземпляр HerClass, сгенерированный из конструктора (new HerClass()). Код скомпилирован, но он не выполнен при выполнении, когда я пытался привести (MyClass) super.clone(). Только методы, связанные с Object.clone(), могут возвращать значение, которое является экземпляром одного из их подтипа .

Обратите внимание, что если HerClass.clone() явно не реализовано, по умолчанию он просто возвращает Object.clone(). Метод по умолчанию имеет доступ protected, но поскольку вы вызываете его из подкласса, это не проблема.

1 голос
/ 28 августа 2011

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

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

Это правда, что метод clone() мог бы быть предоставлен автоматически для всех классов,но иногда вы не хотите, чтобы он был доступен, а иногда вы хотите изменить поведение по умолчанию;например, у вас может быть атрибут id в вашем классе, который вы хотите, чтобы он отличался для каждого экземпляра вашего класса, даже при клонировании.Необходимость переопределить метод clone() дает вам место, где вы можете реализовать такую ​​функциональность.

1 голос
/ 28 августа 2011

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

public Object clone()

, тогда он все равно был бы допустимым клонируемым объектом, и он работал бы.Вам не нужно ничего разыгрывать.Интерфейс Cloneable - это просто маркерный интерфейс, что означает, что на самом деле у него нет никаких методов.

1 голос
/ 28 августа 2011

Потому что clone() возвращает объект класса Object, и вы должны привести его к правильному типу. Но вы знаете, что это объект типа MyClass, так что приведение правильное.

...