Immutability of Strings in Java

2018-12-31 01:41发布

Consider the following example.

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

Now, in Java, String objects are immutable. Then how come the object str can be assigned value "Help!". Isn't this contradicting the immutability of strings in Java? Can anybody please explain me the exact concept of immutability?

Edit:

Ok. I am now getting it, but just one follow-up question. What about the following code:

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!"); 
System.out.println(str); // prints M!ss!ss!pp! 

Does this mean that two objects are created again ("Mississippi" and "M!ss!ss!pp!") and the reference str points to a different object after replace() method?

24条回答
与风俱净
2楼-- · 2018-12-31 02:16

The string object that was first referenced by str was not altered, all that you did was make str refer to a new string object.

查看更多
梦该遗忘
3楼-- · 2018-12-31 02:16

Or you can try:

public class Tester
{
public static void main(String[] args)
{
 String str = "Mississippi"; 
 System.out.println(str); // prints Mississippi 
 System.out.println(str.hashCode());

 str = str.replace("i", "!"); 
 System.out.println(str); // prints M!ss!ss!pp! 
 System.out.println(str.hashCode());
 }
 }

This will show how the hashcode changes.

查看更多
梦醉为红颜
4楼-- · 2018-12-31 02:18

String is immutable means that you cannot change the object itself, but you can change the reference to the object. When you called a = "ty", you are actually changing the reference of a to a new object created by the String literal "ty". Changing an object means to use its methods to change one of its fields (or the fields are public and not final, so that they can be updated from outside without accessing them via methods), for example:

Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"

While in an immutable class (declared as final, to prevent modification via inheritance)(its methods cannot modify its fields, and also the fields are always private and recommended to be final), for example String, you cannot change the current String but you can return a new String, i.e:

String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"
查看更多
栀子花@的思念
5楼-- · 2018-12-31 02:19

The String will not change, the reference to it will. You are confusing immutability with the concept of final fields. If a field is declared as final, once it has been assigned, it cannot be reassigned.

查看更多
人间绝色
6楼-- · 2018-12-31 02:20

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.

查看更多
时光乱了年华
7楼-- · 2018-12-31 02:21

In Java, objects are generally accessed by references. In your piece of code str is a reference which is first assigned to "Hello" (an automatic created object or fetched from constant pool) and then you assigned another object "Help!" to same reference. A point to note is the reference is the same and modified, but objects are different. One more thing in your code you accessed three objects,

  1. When you called new String().
  2. When you assigned "hello".
  3. When you assigned "help!".

Calling new String() creates a new object even if it exists in string pool, so generally it should not be used. To put a string created from new String () into string pool you can try the intern() method.

I hope this helps.

查看更多
登录 后发表回答