简体   繁体   中英

Downcasting while calling super.clone() method

Consider the following program

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

Why output of above program is 1234 and not null.

I was expecting null, because of following understanding of mine.

  1. super.clone() method will create a new object of parent type (Object in this case) in which attributes of parent class will be shallow copied.

  2. When we do downcasting in our clone() method, then attributes defined in child class will get initialised with their default values, since this is a new object.

But after looking at the output, it seems like attribute values of current instance of child class (this) are getting copied to newly contructed object (after calling clone of parent class and downcasting).

Can someone please tell what is going on when we are downcasting?

1234 is the correct result... Let's see why:

Create a new A instance:

A a = new A();

Set value to A.str

a.set("1234");

Clone a

A b = a.clone();

First of all, note, we're using clone() method from instance a , so let's go there:

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

From the Object#clone documentation.

Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression:

x.clone() != x

will be true, and that the expression:

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

will be true, but these are not absolute requirements. While it is typically the case that:

x.clone().equals(x)

will be true, this is not an absolute requirement.

As you can see, the typical case is that X.equals(XClone) == true . This wont be the case for you, as A didn´t override the equals method.

Additonally:

The method clone for class Object performs a specific cloning operation.

[...]

this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.

As this documentation states, the native implementation just creates a shallow copy of the object you are trying to clone. Due to that behaviour the correct output is 1234 and not null , as the fields in the class are just assigned to the cloned instance.

super.clone() method will create a new object of parent type (Object in this case)

No. This is where you are going wrong. Object.clone() will create a new instance of the same runtime class as the runtime class of the object it is called on, which is A , not Object . And it will shallow-copy all of the fields of A in the object it is called on into the new object.

When we do downcasting in our clone() method, then attributes defined in child class will get initialised with their default values, since this is a new object.

That doesn't make any sense because casting references will never affect the state of the object that is pointed to. If the object that the reference points to was not already an instance of A , then the cast will throw a ClassCastException . If the cast succeeds then that means the object that the reference points to was already an instance of A , and you are simply pointing to that same object with a different type of reference. You will never get a "new object" with a cast.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM