Immutability of Strings in Java

str is not an object, it's a reference to an object. "Hello" and "Help!" are two distinct String objects. Thus, str points to a string. You can change what it points to, but not that which it points at.

Take this code, for example:

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

Now, there is nothing1 we could do to s1 that would affect the value of s2. They refer to the same object - the string "Hello" - but that object is immutable and thus cannot be altered.

If we do something like this:

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

Here we see the difference between mutating an object, and changing a reference. s2 still points to the same object as we initially set s1 to point to. Setting s1 to "Help!" only changes the reference, while the String object it originally referred to remains unchanged.

If strings were mutable, we could do something like this:

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

Edit to respond to OP's edit:

If you look at the source code for String.replace(char,char) (also available in src.zip in your JDK installation directory -- a pro tip is to look there whenever you wonder how something really works) you can see that what it does is the following:

  • If there is one or more occurrences of oldChar in the current string, make a copy of the current string where all occurrences of oldChar are replaced with newChar.
  • If the oldChar is not present in the current string, return the current string.

So yes, "Mississippi".replace('i', '!') creates a new String object. Again, the following holds:

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

Your homework for now is to see what the above code does if you change s1 = s1.replace('i', '!'); to s1 = s1.replace('Q', '!'); :)


1 Actually, it is possible to mutate strings (and other immutable objects). It requires reflection and is very, very dangerous and should never ever be used unless you're actually interested in destroying the program.


The object that str references can change, but the actual String objects themselves cannot.

The String objects containing the string "Hello" and "Help!" cannot change their values, hence they are immutable.

The immutability of String objects does not mean that the references pointing to the object cannot change.

One way that one can prevent the str reference from changing is to declare it as final:

final String STR = "Hello";

Now, trying to assign another String to STR will cause a compile error.


Light_handle I recommend you take a read of Cup Size -- a story about variables and Pass-by-Value Please (Cup Size continued). This will help a lot when reading the posts above.

Have you read them? Yes. Good.

String str = new String();

This creates a new "remote control" called "str" and sets that to the value new String() (or "").

e.g. in memory this creates:

str --- > ""

str  = "Hello";

This then changes the remote control "str" but does not modify the original string "".

e.g. in memory this creates:

str -+   ""
     +-> "Hello"

str = "Help!";

This then changes the remote control "str" but does not modify the original string "" or the object that the remote control currently points to.

e.g. in memory this creates:

str -+   ""
     |   "Hello"
     +-> "Help!"

Lets break it into some parts

String s1 = "hello";

This Statement creates string containing hello and occupy space in memory i.e. in Constant String Pool and and assigned it to reference object s1

String s2 = s1;

This statement assigns the same string hello to new reference s2

         __________
        |          |
s1 ---->|  hello   |<----- s2
        |__________| 

Both references are pointing to the same string so output the same value as follows.

out.println(s1);    // o/p: hello
out.println(s2);    // o/p: hello

Though String is immutable, assignment can be possible so the s1 will now refer to new value stack.

s1 = "stack";    
         __________
        |          |
s1 ---->|  stack   |
        |__________|

But what about s2 object which is pointing to hello it will be as it is.

         __________
        |          |
s2 ---->|  hello   |
        |__________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello

Since String is immutable Java Virtual Machine won't allow us to modify string s1 by its method. It will create all new String object in pool as follows.

s1.concat(" overflow");

                 ___________________
                |                   |
s1.concat ----> |  stack overflow   |
                |___________________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello
out.println(s1.concat); // o/p: stack overflow

Note if String would be mutable then the output would have been

out.println(s1);    // o/p: stack overflow

Now you might be surprised why String has such methods like concat() to modify. Following snippet will clear your confusion.

s1 = s1.concat(" overflow");

Here we are assigning modified value of string back to s1 reference.

         ___________________
        |                   |
s1 ---->|  stack overflow   |
        |___________________|


out.println(s1);    // o/p: stack overflow
out.println(s2);    // o/p: hello

That's why Java decided String to be a final class Otherwise anyone can modify and change the value of string. Hope this will help little bit.