0

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?

victini
  • 193
  • 1
  • 6
  • 1
    The `clone()` method is implemented natively in `Object` class, requiring you to use `super.clone();` to invoke it. However it will of course return an object of type `this`, which in your case is `A`. – Kayaman Aug 08 '16 at 11:38

3 Answers3

1

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;    
}
Jordi Castilla
  • 26,609
  • 8
  • 70
  • 109
  • super.clone() method is invoking parent's clone method. So all the attributes which are specific to parent should be shallow cloned. But in the program "str" is attribute of subclass and not parent class. Then who is responsible for it's cloning? – victini Aug 08 '16 at 11:57
  • not exactly, please kindly take a look at this discussion http://stackoverflow.com/questions/1067383/confusion-about-cloneable-interface-and-object-clone-in-java – Jordi Castilla Aug 08 '16 at 12:06
1

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.

SomeJavaGuy
  • 7,307
  • 2
  • 21
  • 33
  • super.clone() method is invoking parent's clone method. So all the attributes which are specific to parent should be shallow cloned. But in the program "str" is attribute of subclass and not parent class. Then who is responsible for it's cloning? – victini Aug 08 '16 at 11:57
  • @victini [check this answer aswell](http://stackoverflow.com/questions/5375311/how-does-object-class-implement-clone-method). The native implementation from `Object` simply assigns each field of the actuall class, and not everything that just corresponds to the class `Object`. – SomeJavaGuy Aug 08 '16 at 12:00
0

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.

newacct
  • 119,665
  • 29
  • 163
  • 224