2

I just wanted to create a shallow and a deep copy of an object. I know that in the deep copy you create a new object with the values of the object you want to copy to prevent a side effect. The thing I noticed I can't get a side effect on my shallow copy, but I don't understand why.

public class Joo {
    public String name;
    
    public Joo(String a) {
        this.name = a; 
    }
    public Joo(Joo a) {
        this.name = a.name; 
    }
    
    public static void main(String[] args) {
        Joo a = new Joo("Bernt");
        Joo b = new Joo(a);
        
        System.out.println("a :" +a.name); //a :Bernt
        System.out.println("b :" +b.name); //b :Bernt

        b.name = "Ernie";
        System.out.println("a :" +a.name); //a :Bernt 
        System.out.println("b :" +b.name); //b :Ernie
    }
}

I was expected that when I change b.name its also changes a.name because b.name is just the reference of the a.name object and not a real copy.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
John Sace
  • 23
  • 4
  • 1
    "because b.name is just the reference of the a.name object and not a real copy" Yeah, but by doing `b.name = "Ernie"`, you are making `b.name` refer to something else. It no longer is "just the reference of the a.name object". – Sweeper Aug 12 '23 at 12:41
  • Wow thank you for the quick answer :) . Okay than I got the sideeffect part wrong. How do I then force a sideeffect ? – John Sace Aug 12 '23 at 12:44
  • Both are a deep copy... Your second constructor is identical to calling `this(a.name)`, that is, calling your first constructor. – Mark Rotteveel Aug 12 '23 at 16:09

1 Answers1

3

because b.name is just the reference of the a.name object and not a real copy"

Yeah, that is true, until you wrote b.name = "Ernie". That makes b.name a reference to something else (namely, the string "Ernie"). That is what the = operator does. b.name no longer is "just the reference of the a.name object".

So you need to change b.name in some way, without making it a reference to something else.

However, there is no way to do this. String is immutable. After the String is created, there is no method you can call, or (public) fields you can set, that can change what string the String object represents. On the other hand, you can assign a new object to an existing String, like you are doing here.

Arguably, this is one of the reasons why String is immutable. Making a shallow copy of String will not cause any unwanted side effects, so you don't actually need to deep copy Strings.

To see the side effects, use a mutable type, like StringBuilder:

public class Joo {
    public StringBuilder name;

    public Joo(String a) {
        this.name = new StringBuilder(a);
    }

    public Joo(Joo a) {
        this.name = a.name;
    }
}

Rather than assigning a new instance of StringBuilder, mutate the object by calling one of its methods:

b.name.append("Something");

Now it prints:

a :Bernt
b :Bernt
a :BerntSomething
b :BerntSomething
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Wow thank sooo much , I got it now. I never new that a String is immutable because all the examples for a shallow copy form my professor stated that the shallowCopy can now also change the original String. Now I am really confused why she said that. – John Sace Aug 12 '23 at 13:01