0
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 ?

narendra
  • 11
  • 1
  • `(s1 == s4); // Expected false. But it is true` let me ask counter-question: why do you expect `false` here? – Pshemo Dec 01 '20 at 22:04
  • Take a look here, maybe it can help you: https://stackoverflow.com/questions/10578984/what-is-java-string-interning – dextertron_ Dec 01 '20 at 22:06
  • Main purpose of string pool is to let us reuse strings which have a chance to reappear in code execution. For instance when you have `for (...){System.out.println("Name: "); ...}` then String `"Name: "` shouldn't be created in each iteration. Instead it should be cached and reused. So when you write something like `String str = "foo";` Java will first try to find `foo` in pool. If it was found it will assign to `str` reference to that cached `"foo"`. If not found it will place it in pool. – Pshemo Dec 01 '20 at 22:18
  • So at `String s3 = "HelloWorld";` it tries to find `HelloWorld` in string pool and since such string exists there (was placed at line 2) it reuses it. – Pshemo Dec 01 '20 at 22:18
  • @narendra But *why* do you expect `false` there? Line 2 checks if string pool contains `HelloWorld`, it doesn't so it places `s1` there. Line 4 also checks if string pool contains `HelloWorld`, since it does it returns it (and that is same String which was placed earlier in Line 2, and which was created at Line 1). – Pshemo Dec 01 '20 at 23:29
  • @Pshemo, Thanks for the reply. s1 is created in heap memory. s3 is supposed to be created in SCP (because we have given String s3 = "HelloWorld";). Why s1==s3 is true ? I expected s1==s4 is false because s1 is in heap. 'String s4 = s1.intern(); ' By the time this line got executed, the result of s1.intern() will check the value "HelloWorld" is in SCP. "HelloWorld" should be in SCP because of 'String s3 = "HelloWorld";'. Since it is present in SCP, s4 refers the object in SCP. So, i expect s1==s4 is false. isn't it right ? – narendra Dec 02 '20 at 19:11
  • @narendra Just to be clear: SCP is also on the heap (just like any other object). You can think of SCP as `Collection SCP = new ...` which simply stores *references* to String objects. "*s3 is supposed to be **created** in SCP*" String literals are compiled in a way to first check if SCP already possess such String. If yes reuse it. Only if SCP doesn't contain such string it will be added **but that is not the case here**. – Pshemo Dec 02 '20 at 22:25
  • Notice that at Line 1 you created String which *represents* text `HelloWorld`. At Line 2 you *interned* it and since SCP at that time didn't contain any String also representing same text it was successfully added there (the one which was held by `s1` and also returned by `indent()` method - so same String is also referenced by `s2` variable). Now at Line 3 since SCP already contains String representing `HelloWorld` it will be reused and assigned to `s3` (NO new string is placed in SCP here, there is no point in that). – Pshemo Dec 02 '20 at 22:25

1 Answers1

1

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

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • _The result is as seen: s1, s2, s3, and s4 all reference the same object._ Are you saying that all these s1, s2, s3 and s4 pointing to objects in SCP or Heap memory. If you say that all are pointing to Heap memory, How can s3 refer to Heap when I have clearly declared String s3 = "HelloWorld"; If you say that all are pointing to SCP, How can s1 refer to SCP when I have clearly declared String s1 = "Hello".concat("World"); – narendra Dec 02 '20 at 12:49
  • 1
    @narendra Why do you believe that the `String` objects in the SCP are not themselves stored in the Heap? The SCP *might* be implemented as a simple `Map`, which is also in the Heap, which would mean that the entire SCP is in the Heap. – Andreas Dec 02 '20 at 20:07
  • Hi @Andreas, I understand that SCP is part of Heap. My only concern is when I declare String s3 = "HelloWorld", I believe that is in SCP. But it confirms that there are cases where it is not in SCP. Thanks for explanation. – narendra Dec 02 '20 at 22:56