Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the following example seem to refute that Strings are immutable objects in Java?

I am using the OpenJDK Java compiler under Ubuntu. I wanted to convert a character array to a string and when that seemed to have ended up giving ambiguous results, I tried to write a toString method of my own. In the process, I wrote a test program wherein (out of the fun of it) I tried to compile the following code.

class toString{
    public static void main(String[] args){
        string = "abc";
        string = string + "bcd";
        System.out.println(string);
    }
}

Now, I know that String objects in Java are immutable and the code should have in fact generated an error but to my surprise, it printed abcbcd to the console. Does this mean that String objects in Java are mutable or is there something wrong with the implementation of OpenJDK compiler in this case?

like image 231
sidharth sharma Avatar asked Nov 28 '22 14:11

sidharth sharma


1 Answers

The code that you've posted above does not actually mutate any strings, though it looks like it does. The reason is that this line doesn't mutate the string:

string = string + "bcd";

Instead, what this does is:

  1. Construct a new string whose value is string + "bcd".
  2. Change what string is referenced by string to refer to this new string.

In other words, the actual concrete string objects themselves weren't changed, but the references to those strings were indeed modified. Immutability in Java usually means that objects cannot be modified, not the references to those objects.

An important detail that confuses a lot of new Java programmers is that the above line is often written as

string += "bcd";

which looks even more strongly as though it's concatenating bcd onto the end of the string and thereby mutating it, even though it's equivalent to the above code and therefore doesn't cause any changes to the actual String object (again, it works by creating a new String object and changing what object the reference refers to.)

To see that what's going on here is that you're actually changing the reference and not the string it refers to, you can try rewriting the code to make string final, which prevents you from changing what object is referenced. If you do so, you'll find that the code no longer compiles. For example:

class toString{
    public static void main(String[] args){
        final String string = "abc";
        string = string + "bcd";    // Error: can't change string!
        System.out.println(string);
    }
}

One final note - another common cause of grief for new Java programmers when using Strings is that String has methods that appear to mutate the string but in actuality do not. For example, this code does not work correctly:

String s = "HELLO, WORLD!";
s.toLowerCase(); // Legal but incorrect
System.out.println(s); // Prints HELLO, WORLD!

Here, the call to s.toLowerCase() does not actually convert the characters of the string to lower case, but instead produces a new string with the characters set to lower case. If you then rewrite the code as

String s = "HELLO, WORLD!";
s = s.toLowerCase();   // Legal and correct
System.out.println(s); // Prints hello, world!

Then the code will behave properly. Again, the key detail here is that the assignment to s does not change any concrete String object, but just adjusts what object s refers to.

Hope this helps!

like image 160
templatetypedef Avatar answered Dec 10 '22 15:12

templatetypedef