Question

I have this code in Java.

public class CloneTest implements Cloneable{
    String name;
    int marks;
    public CloneTest(String s, int i) {
        name = s;
        marks = i;
    }

    public void setName(String s) {
        name = s;
    }

    public void setMarks(int i) {
        marks = i;
    }

    @Override
    public Object clone() {
        return new CloneTest(this.name, this.marks);
    }
}

I have created one object of this class, and then cloned it. Now, when I change the value of name in one object, the value of name remains unchanged in the other. The strange thing here is in the constructor, I am just using a simple reference for name, not creating a new String for name. Now, since Strings are reference types, I expected the String in the clone to be changed as well. Can anyone tell me what's going on? Thanks in advance!

EDIT

Code Testing

CloneTest real = new CloneTest("Molly", 22);
CloneTest clone = real.clone();
real.setName("Dolly");

I used the "Inspect Variables" feature of BlueJ to check the values.

Was it helpful?

Solution

Assume that original is the name of original CloneTest object, and cloned is the cloned object that you created from original using the clone() method.

This is what happened:
1. Your cloned.name and original.name are pointing at the same object, which in this case was a String.
2. Then you asked your original.name to point to a different String object ("Dolly"). This happens when you assign the new String object ("Dolly") to the reference original.name.
3. But, the cloned.name still points to the first String object ("Dolly").

Hence, cloned.name still prints the 1st String object.

Now, if you are able to change the content of the String object without reassigning the references, then the change in clone.name will reflect in original.name. But for String objects, this is not possible due to the immutability of Strings. However, you can reflect the change from the clone to original with StringBuffers which are mutable strings so to speak. Take a look at this example code for the same: https://gist.github.com/VijayKrishna/5967668

OTHER TIPS

Each instance of your class has different references to an object. You you're just changing reference not modifying object. If you place your string in some holder object, then clone it and set string inside the holder (not a holder reference but string reference inside holder) then you'll have your changes in both of clones

So are you saying you are doing something like:

 public void testSomeMethod() {

      CloneTest a = new CloneTest("a", 1);

      CloneTest b = (CloneTest) a.clone();

      a.setName("b");

      assertFalse(b.name.equals(a.name));
      assertEquals("b", a.name);
      assertEquals("a", b.name);  
  }

?

If so, then all these assertions should pass. Your clone method has reference types in it, and when initially cloned, they refer to the same object. But the setName("...") changes the value that instance points to, not the value of the referred to object.

Get some better clarity along with @vijay answer by looking hash code.

    CloneTest real = new CloneTest("Molly", 22);
    CloneTest clone = (CloneTest) real.clone();
    int h1=real.name.hashCode();
    int h2=clone.name.hashCode();
    System.out.println("h1 "  + h1  + " h2 " + h2); // same
    real.setName("sak");
    h1=real.name.hashCode();
    h2=clone.name.hashCode();
    System.out.println("h1 "  + h1  + " h2 " + h2); //different

Output :

 h1 74525175 h2 74525175
 h1 113629 h2 74525175
package com.test;
class Manager implements Cloneable
{
String firstName;
String lastName;
int age;
public Manager(String fname,String lname,int a)
{
    this.firstName=fname;
    this.lastName=lname;
    this.age=a;
}
public String getFirstName() {
    return firstName;
}
public void setFirstName(String firstName) {
    this.firstName = firstName;
}
public String getLastName() {
    return lastName;
}
public void setLastName(String lastName) {
    this.lastName = lastName;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return super.clone();
}

}

public class TestCloning {
public static void main(String[] args) throws CloneNotSupportedException {
    Manager m1=new Manager("Sadik","Tahir",26);
    Manager m_clone=(Manager)m1.clone();
    Manager m2=m1;
    System.out.println("M1 Details:::");
    System.out.println("Fisrt Name:"+m1.getFirstName()+",LastName:"+m1.getLastName()+",Age:"+m1.getAge());
    System.out.println("Hashcode:"+m1.hashCode());
    System.out.println("M_Clone Details:::");
    System.out.println("Fisrt Name:"+m_clone.getFirstName()+",LastName:"+m_clone.getLastName()+",Age:"+m_clone.getAge());
    System.out.println("Hashcode:"+m_clone.hashCode());
    System.out.println("M2 Details:::");
    System.out.println("Fisrt Name:"+m2.getFirstName()+",LastName:"+m2.getLastName()+",Age:"+m2.getAge());
    System.out.println("Hashcode:"+m2.hashCode());
    m1.setFirstName("Afreen");
    m1.setLastName("Khan");
    m1.setAge(25);
    System.out.println("M1 Details:::");
    System.out.println("Fisrt Name:"+m1.getFirstName()+",LastName:"+m1.getLastName()+",Age:"+m1.getAge());
    System.out.println("Hashcode:"+m1.hashCode());
    System.out.println("M_Clone Details:::");
    System.out.println("Fisrt Name:"+m_clone.getFirstName()+",LastName:"+m_clone.getLastName()+",Age:"+m_clone.getAge());
    System.out.println("Hashcode:"+m_clone.hashCode());
    System.out.println("M2 Details:::");
    System.out.println("Fisrt Name:"+m2.getFirstName()+",LastName:"+m2.getLastName()+",Age:"+m2.getAge());
    System.out.println("Hashcode:"+m2.hashCode());
}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top