2016-08-08 14 views
0

Рассмотрим следующую программупонижающее приведение при вызове super.clone() метод

class A implements Cloneable { 
    String str = null; 
    public void set(String str) 
    { 
     this.str = str;  
    } 

    @Override 
    public A clone() 
    { 
     A a = null; 
     try { 
       a = (A) super.clone(); 
       if(a.str!=null) { 
        System.out.println(a.str); 
       } 
       else { 
        System.out.println("null"); 
       } 

     } 
     catch (CloneNotSupportedException e) { 
       e.printStackTrace(); 
     } 
     return a;  
    } 
    public static void main (String args[]) 
    { 
     A a = new A(); 
     a.set("1234"); 
     A b = a.clone(); 
    } 
} 

Почему выход выше программы 1234, а не нулевой.

Я ожидал null, из-за нижеследующего понимания.

  1. метод super.clone() создает новый объект родительского типа (Object в данном случае), в котором атрибуты родительского класса будет скопирован мелким.

  2. Когда мы применяем метод downone в нашем методе clone(), атрибуты, определенные в дочернем классе, будут инициализированы с их значениями по умолчанию, поскольку это новый объект.

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

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

+1

Метод 'clone()' реализуется изначально в классе 'Object', требуя, чтобы вы использовали' super.clone(); 'для его вызова. Однако он, конечно, вернет объект типа 'this', который в вашем случае равен' A'. – Kayaman

ответ

1

1234 правильный результат ... Давайте посмотрим, почему:

Создать новый экземпляр A:

A a = new A(); 

Установленное значение для A.str

a.set("1234"); 

клонировать

A b = a.clone(); 

Прежде всего, обратите внимание, что мы используем метод clone() от экземпляра a, так что давайте идти туда:

@Override 
public A clone() 
{ 
    // create a NEW instance, it does not set a to null!!! 
    // to reference the caller (a.clone in main) 
    // you must use this keyword i.e: this.str = null 
    A a = null; 
    try { 
      // call Cloneable::clone() method 
      a = (A) super.clone(); 

      // now a is filled with data of this instance so print 1234 
      if(a.str!=null) { 
       System.out.println(a.str); 
      } 
      // unused code in this case 
      else { 
       System.out.println("null"); 
      } 

    } 
    catch (CloneNotSupportedException e) { 
      e.printStackTrace(); 
    } 
    // return cloned instance 
    return a;  
} 
+0

Метод super.clone() вызывает метод клонирования родителя. Таким образом, все атрибуты, специфичные для родителя, должны быть клонированы неглубоко. Но в программе «str» есть атрибут подкласса, а не родительский класс. Тогда кто несет ответственность за его клонирование? – victini

+0

не совсем, пожалуйста, любезно рассмотрите эту дискуссию http://stackoverflow.com/questions/1067383/confusion-about-cloneable-interface-and-object-clone-in-java –

1

Из документации Object#clone.

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

x.clone() = х

будет справедливо, и что выражение:!.

x.clone() GetClass() == x.getClass()

будет правдой, но это не абсолютные требования. В то время как это обычно бывает, что:.

x.clone() равно (х)

будет верно, это не является абсолютным требованием.

Как вы можете видеть, типичным случаем является то, что X.equals(XClone) == true. Это не относится к вам, так как A не переопределил метод equals.

Additonally:

Метод клон для класса Object выполняет определенную операцию клонирования.

[...]

этот метод создает новый экземпляр класса этого объекта и инициализирует все его поле с точно содержанием соответствующих полей этого объекта, как по заданию; содержимое полей само по себе не клонируется. Таким образом, этот метод выполняет «мелкую копию» этого объекта, а не операцию «глубокой копии».

Как указано в этой документации, встроенная реализация только создает объект shallow copy объекта, который вы пытаетесь клонировать. Из-за этого поведения правильный вывод равен 1234, а не null, так как fields в классе присваивается только клонированному экземпляру. Метод

+0

метод super.clone() вызывает родительский метод клонирования. Таким образом, все атрибуты, специфичные для родителя, должны быть клонированы неглубоко. Но в программе «str» есть атрибут подкласса, а не родительский класс. Тогда кто несет ответственность за его клонирование? – victini

+0

@victini [также проверьте этот ответ] (http://stackoverflow.com/questions/5375311/how-does-object-class-implement-clone-method). Нативная реализация из 'Object' просто присваивает каждому полю класса actall, а не все, что соответствует классу' Object'. – SomeJavaGuy

0

super.clone() создаст новый объект родительского типа (Object в данном случае)

No. Это где вы собираетесь не так. Object.clone() создаст новый экземпляр того же класса времени выполнения, что и класс времени выполнения объекта, на который он вызывается, который равен A, а не Object. И он покроет все поля A в объекте, который он вызывает в новый объект.

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

Это не имеет никакого смысла, поскольку ссылки на литье никогда не повлияют на состояние объекта, на который указывает. Если объект, на который ссылается ссылка, еще не был экземпляром A, то бросок будет бросать ClassCastException. Если листинг преуспевает, это означает, что объект, на который ссылаются точки ссылки, уже был экземпляром A, и вы просто указываете на тот же объект с другим типом ссылки. Вы никогда не получите «новый объект» с броском.