Java String‘s Immutability

一、Diagram to show Java String’s Immutability
1.Declare a string
String s = "abcd";

The variable s stores the reference of a string object as shown below. The arrow can be interpreted as “store reference of”.

在这里插入图片描述

2. Declare another string

The following code assign s to s2.

String s2 = "abcd";

s2 stores the same reference value since it is the same string object.

在这里插入图片描述

3.Concat string

When we concatenate a string “ef” to s,

s = s.concat("ef");

s stores the reference of the newly created string object as shown below.
在这里插入图片描述

4. new operator

If you are confused, please continue reading the following: Java String Pool
在这里插入图片描述

Summary

In summary, once a string is created in memory(heap), it can not be changed. All methods of String do not change the string itself, but rather return a new String.

If we need a string that can be modified, we will need StringBuffer or StringBuilder. Otherwise, there would be a lot of time wasted for Garbage Collection, since each time a new String is created. Here is an example of using StringBuilder.

二、 Java String Pool
1. String Interning

Thanks to the immutability of Strings in Java, the JVM can optimize the amount of memory allocated for them by storing only one copy of each literal String in the pool. This process is called interning.

When we create a String variable and assign a value to it, the JVM searches the pool for a String of equal value.

If found, the Java compiler will simply return a reference to its memory address, without allocating additional memory.

If not found, it’ll be added to the pool (interned) and its reference will be returned.

Let’s write a small test to verify this:

String constantString1 = "Baeldung";
String constantString2 = "Baeldung";
         
assertThat(constantString1)
  .isSameAs(constantString2);
2. String Literal vs String Object

When we create a String object using the new() operator, it always creates a new object in heap memory. On the other hand, if we create an object using String literal syntax e.g. “Baeldung”, it may return an existing object from the String pool, if it already exists. Otherwise, it will create a new String object and put in the string pool for future re-use.

At a high level, both are the String objects, but the main difference comes from the point that new() operator always creates a new String object. Also, when we create a String using literal – it is interned.

This will be much more clear when we compare two String objects created using String literal and the new operator:

String first = "Baeldung"; 
String second = "Baeldung"; 
System.out.println(first == second); // True

In this example, the String objects will have the same reference.

Next, let’s create two different objects using new and check that they have different references:

String third = new String("Baeldung");
String fourth = new String("Baeldung"); 
System.out.println(third == fourth); // False

Similarly, when we compare a String literal with a String object created using new() operator using the == operator, it will return false:

String fifth = "Baeldung";
String sixth = new String("Baeldung");
System.out.println(fifth == sixth); // False

In general, we should use the String literal notation when possible. It is easier to read and it gives the compiler a chance to optimize our code.

3. Manual Interning

We can manually intern a String in the Java String Pool by calling the intern() method on the object we want to intern.

Manually interning the String will store its reference in the pool, and the JVM will return this reference when needed.

Let’s create a test case for this:

String constantString = "interned Baeldung";
String newString = new String("interned Baeldung");
 
assertThat(constantString).isNotSameAs(newString);
 
String internedString = newString.intern();
 
assertThat(constantString)
  .isSameAs(internedString);
三、 Why String is immutable in Java?

1. Synchronization
Being immutable automatically makes the String thread safe since they won’t be changed when accessed from multiple threads.
Hence immutable objects, in general, can be shared across multiple threads running simultaneously. They’re also thread-safe because if a thread changes the value, then instead of modifying the same, a new String would be created in the String pool. Hence, Strings are safe for multi-threading.

2. Security
A String is used as an argument for class loading. Let’s imagine what will happen if String is mutable. In that case, the value of the object can be changed and wrong class can be loaded.

Immutability provides security so that the correct class is getting loaded by the Classloader. For example, we want to load the com.generic.class.PasswordChecker class to verify the user password, but perhaps, the referenced value can be changed to com.hacked.PasswordChacker.
In class loading, we have seen how String immutability helps in loading the correct class and provides security. There are other examples where String immutability helps in gaining security.

For example, in a banking application, the username, password, bank account details, etc. are passed as the String. As String is immutable, its value can’t be changed. Otherwise, any hacker could change the referenced value to cause security issues.

3. Perfect Candidate for HashMap Key
String is mostly used as the Object to HashMap keys. Since String is immutable, its hashcode is cached at the time of creation and doesn’t need to be calculated again. This makes it a great candidate for the key in a Map, and it’s processing is fast than other HashMap key objects.

4. String pool
String pool is possible only because String is immutable in Java. This way Java Runtime saves a lot of heap space because different String variables can refer to the same String variable in the pool. If String would not have been immutable, then String interning would not have been possible because if any variable would have changed the value, it would have been reflected in the other variables too.

四、Key points
  1. It is only string literals (see notes) that get automatically interned / added to the string pool. String objects that are created by an application at runtime are not interned … unless your application explicitly calls String.intern().
  2. In fact the rules for garbage collecting objects in the string pool are the same as for other String objects: indeed all objects. They will be garbage collected if they ever become unreachable.
  3. In practice, the String objects that correspond to string literals typically do not become candidates for garbage collection. This is because there is an implicit reference to the String object in the code of every method that uses the literal. This means that the String is reachable for as long as the method could be executed.
  4. Stay away from String.intern() method on Java 6 due to a fixed size memory area (PermGen) used for JVM string pool storage.
  5. Java 7 and 8 implement the string pool in the heap memory. It means that you are limited by the whole application memory for string pooling in Java 7 and 8.
  6. Use -XX:StringTableSize JVM parameter in Java 7 and 8 to set the string pool map size. It is fixed, because it is implemented as a hash map with lists in the buckets. Approximate the number of distinct strings in your application (which you intend to intern) and set the pool size equal to some prime number close to this value multiplied by 2 (to reduce the likelihood of collisions). It will allow String.intern to run in the constant time and requires a rather small memory consumption per interned string (explicitly used Java WeakHashMap will consume 4-5 times more memory for the same task).
五、Wrong Assumption

If String is immutable, why is the following statement allowed?

String a = “Generic Class”;
a = “www.genericclass.com”;

One can say in the above statements that they are able to change the value of a String object from “Generic Class” to “www.genericclass.com." Then, what exactly does String immutability mean?

But wait, this assumption is wrong. In the above statements, you are not changing the value of the String object. Here, you are basically changing the reference. Previously, your variable a was pointing to an object that had the value “Generic Class."

But, in the second statement, a new object is created with value “www.genericclass.com” and your variable started to point to this new object.
在这里插入图片描述
The older object still has the value “Generic Class.”

参考:
《Diagram to show Java String’s Immutability》
《Guide to Java String Pool》
《String: Why it Is Immutable?》
《Why String is Immutable in Java?》
《Java Performance Tuning Guide》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值