String intern, String concatenation and String constant pool example in java

362 Views Asked by At
package com.lang;

class StringConcatDemo2
{
   public static void main(String[] args)
   {
      String s1 = "Hello".concat("World"); // s1 to be created in heap.
      String s2 = s1.intern(); //Line-2   //Since "HelloWorld" doesn't exist in String constant pool (SCP), s1 and s2 point the same.      
      String s3 = "HelloWorld"; //Line-3  s3 to be created in SCP.
      String s4 = s1.intern();  //Since "HelloWorld" exists in SCP, s3 & s4 should refer to String in SCP.
      System.out.println(s1 == s2); // true
      System.out.println(s1 == s4); // Expected false. But it is true.
      System.out.println(s1 == s3); // Expected false. But it is true. 
      System.out.println(s3 == s4); //true
   }
} 

Why s1 and s4 are referring same object in Heap ? Why s1 and s3 are referring same object in Heap ? When I swap Line-2 and Line-3, the o/p is meeting my expectation (o/p: false, false, false, true)

Can someone please explain me in detail ?

1

There are 1 best solutions below

3
On

Since "HelloWorld" is in the source file, the generated .class file contains that string constant, and the string constant is added to the String constant pool (SCP) when the class definition is loaded into the JVM.

That means that we would expect s2, s3, and s4 to all refer to the string in the SCP.

Don't know why "Hello".concat("World") ends up referring to the SCP instance, though it's likely an optimization that's implemented in the JVM, because concat() is a well-known string method, and strings are well-known to be memory hogs.

In contrast, "Hello" + "World" would also be expected to refer to the SCP instance, because the Java compiler can evaluate that constant expression to "HelloWorld", as can be seen if disassembling the .class bytecode using javap.


UPDATED

It seems that I was mistaken, and string constants in the .class file are not added to the SCP when the class is loaded, but when the string constant is first used.

Which means that the sequence is as follows:

  1. s1 is assign string "HelloWorld", which is not in SCP.

  2. s1.intern() adds the string referenced by s1 to the SCP, and s2 is assigned that same reference value.
    Result: s2 = s1

  3. String constant "HelloWorld" is resolved by the JVM, and since it is already in SCP, the SCP instance is returned.
    Result: s3 = s1

  4. s3.intern() simply returns s3 since it's already in SCP.
    Result: s4 = s3 = s1

The result is as seen: s1, s2, s3, and s4 all reference the same object.

If the order of the code is changed, the result is different, leading credence to this:

String s1 = "HelloWorld";
String s2 = s1.intern();
String s3 = "Hello".concat("World");
String s4 = s1.intern();
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // true
  1. String constant "HelloWorld" is resolved and added to SCP. s1 is assigned the SCP instance.

  2. s1.intern() simply returns s1 since it's already in SCP.
    Result: s2 = s1

  3. concat() creates new instance of "HelloWorld" in the heap, and assigns that to s3.
    Result: s3 != s1

  4. s3.intern() adds the string referenced by s1 to the SCP, and s2 is assigned that same reference value.
    Result: s4 = s1