Унижение во время вызова метода 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, а не нуль.

Я ожидал ноль из-за моего понимания.

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

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

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

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

3 ответа

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;    
}

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

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

x.clone ()! = x

будет верно, и это выражение:

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

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

x.clone (). равенства (х)

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

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

Additonally:

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

[...]

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

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

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

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

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

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

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