Ответ 1
В принципе, поскольку метод clone()
делает то, что вы не можете сделать на языке Java: он клонирует состояние объекта, включая его фактическое обозначение класса.
Механизм клонирования в Java основан на каждом классе, вызывающем метод суперкласса clone
, вплоть до Object
. Затем объект использует этот "магический" родной метод clone
для дублирования исходного объекта, включая его фактический класс.
Подумайте об этом:
class A implements Cloneable {
public A clone() {
A obj = (A) super.clone();
// Do some deep-copying of fields
return obj;
}
}
class B extends A {
public B clone() {
B obj = (B) super.clone();
// Do some deep-copying of fields not known to A
return obj;
}
}
Теперь представьте, что у вас есть объект типа B
, и вы вызываете clone
на нем. Вы ожидаете получить объект B
, класс которого внутренне распознан как B
, а не как Object
. B
не знает реализации всего в A
, и поэтому ему нужно вызвать метод A
clone
. Но если A
реализовал clone
на языке Java, а не вызывал super.clone()
, то возвращаемый им объект должен был бы быть A
. Он не может использовать new B()
(предполагается, что B не был известен, когда был создан A).
Он мог бы что-то сделать с отражением, но как бы он знал, какой конструктор должен вызвать так, чтобы все конечные поля были правильно заполнены?
Итак, трюк заключается в том, что A
не делает это сам, он вызывает super.clone()
, и это полностью возвращается к Object
, и он использует собственный метод, который побайтно копирование исходного объекта, настройка для нового местоположения кучи. Таким образом, новый объект магически становится объектом B
, и литье типов не будет терпеть неудачу.
Почему бы не вернуть Object
? Потому что это не клонирование. Когда вы вызываете clone
, вы ожидаете получить объект как с одним и тем же состоянием (поля), так и с тем же классом (переопределенные и добавленные методы). Если он возвратил объект, чье внутреннее обозначение класса было Object
, у вас был бы доступ только к тем вещам, которые Object
предлагает, например toString()
, и вы не сможете получить доступ к своим закрытым полям из другого B
объект или присвоить его переменной типа B
.