简体   繁体   中英

Are Strings *really* immutable in Java?

Everyone knows that Java's String object is immutable which essentially means that if you take String object a and concatenate it with another String object, say b , a totally new String object is created instead of an inplace concatenation.

However, recently I have read this question on SO which tells that the concatenation operator + is replaced with StringBuilder instances by the compiler.

At this point, I get a bit confused since, as far as I know and think, the StringBuilder objects are mutable due to their internal structure. In this case, wouldn't this essentially make String objects in Java mutable ?

Not really.

The actual Strings are still immutable, but in compile time, the JVM can detect some situations where the creation of additional String objects can be replaced by a StringBuilder.

So if you declare a String a and concatenate with another String, your a object doesn't change, (since it's immutable), but the JVM optimizes this by replacing the concatenation with the instantiation of a StringBuilder, appending both Strings to the Builder, and finally assigning the resulting String.

Let's say you have:

String a = "banana";
String d = a + "123" + "xpto";

Before the JVM optimized this, you would essentially be creating a relatively large number of Strings for something so simple, namely:

  • String a
  • String "123"
  • String "xpto"
  • String a + "123"
  • String a+"123"+"xpto"

With the optimization of transforming concatenation into a StringBuilder, the JVM no longer needs to create the intermediate results of the concatenation, so only the individual Strings and the resulting one are needed.

This is done basically for performance reasons, but keep in mind that in certain situations, you'll pay a huge penalty for this if you aren't careful. For instance:

String a = "";
for(String str: listOfStrings){
    a += str;
}

If you were doing something like this, in each iteration the JVM will be instantiating a new StringBuilder, and this will be extremely costly if listOfStrings has a lot of elements. In this case, you should use a StringBuilder explicitly and do appends inside the loop instead of concatenating.

Strings are immutable objects. Once you concatenate it with another String, it becomes a new object. So remember - you don't change the existing String, you just create a new one.

Strings really are immutable. The compiler may generate code involving StringBuilder , but that is just an optimization which does not change how the code behaves (apart from performance). If there was some case where you could observe mutation (eg by keeping a reference to one of the intermediate results), the compiler would have to optimize in a way that still gives you an immutable string for that intermediate reference.

So if StringBuilder is used under the covers, even if you can't directly see the difference, doesn't that still mean that mutability is involved? Well, yes, but if you get down to it all the RAM in your PC is mutable. The memory of immutable objects can be moved around by the garbage collector, which definitely involves mutation as well. In the end, the important thing to you as a programmer is that this mutation is hidden from you, and you get a big promise that your program will behave the way you expect, ie you'll never see mutation in an immutable object (except in cases of severe problems, eg faulty RAM).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM