Java: Why String is special in Deep Copy and Shallow copy?

These days I am learning the clone method of Java. I learned that clone uses shallow copy. If I want to implement a deep copy of an object, then I should follow the following principles from this website

No need to separately copy primitives. All the member classes in original class should support cloning and in clone method of original class in context should call super.clone() on all member classes.

In my understanding, String in Java is a kind of reference, in order to better express my point of view, this is the code:

// User.java
public class User implements Cloneable{
    private String name;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // Getter() ,setter() and toString() are omitted here
}

And the following code is the test code:

User user = new User();
user.setName("one");

User clone = (User)user.clone();
clone.setName("two");

System.out.println(user.getName());     // I think it should print "two", but actually "one"

So in my example, it seems I create a Deep Copy of User(do I?)

Here is my understanding of Java memory:

①means I create a copy, ② is the change of the String.

So if my picture is correct, it should print “two”, right?

I know the String in java is immutable, and I think this is probably the reason why this happens, but I don’t know how does this happens and the reason why this happens.


According to @Jesper’s picture, I create a new picture to explain my question more specifically.

And the demo code:

public class Employee implements Cloneable {

    private int employeeId;
    private String employeeName;
    private Department department;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();   // shallow copy
    }

    // Getter() ,setter() and toString() are omitted here
}
public class Department{
    private int id;
    private String name;

    // Getter() ,setter() and toString() are omitted here
}

Test code:

Department hr = new Department(1, "Human Resource");
Employee original = new Employee(1, "Admin", hr);
Employee cloned = (Employee) original.clone();
cloned.getDepartment().setName("Finance");
System.out.println(original.getDepartment().getName());  //print Finance

And the picture:

The red part is the key. If it is the java.lang.String object, it will create a new one(from “one” to “two” as above showed), but if it is another class object(Here is Department class) then it seems there will be only one object(instead of creating one), so my question is Why String is special in Deep Copy and Shallow copy? Is this related to String immutability?

Thanks in advance!

Answer

You start with this situation:

enter image description here

Then you clone the User object. You now have two User objects; the variables user and clone refer to those two objects. Note that both their name member variables refer to the same String object, with the content "one".

enter image description here

Then you call setName("two") on clone, which will change the name member variable of the second User object to refer to a different String object, with the content "two".

enter image description here

Note that the variable user still refers to the User object which has its name member variable referring to "one", so when you System.out.println(user.getName()); the result is one.

Leave a Reply

Your email address will not be published. Required fields are marked *