2
13: String a = "";
14: a += 2;
15: a += 'c';
16: a += false; 
17: if ( a == "2cfalse") System.out.println("==");
18: if ( a.equals("2cfalse")) System.out.println("equals");

Output: equals

Please correct me if I am wrong...

At line 13 a new String object is created and the reference is stored at a. (a = "")

At line 14 a new String object is created and the reference is stored in a. The previous String object becomes eligible of garbage collection(GC). (a = "2c")

At line 15 a new String object is created and the reference is stored in a. The previous String object becomes eligible of garbage collection(GC). (a = "2cfalse").

Now, the String pool consists of the 2cfalse literal. Therefore, at line-17, shouldn't a == "2cfalse" evaluate to true since they are both pointing to the same object in memory?

However, the program output is just ==. Where did I go wrong? Please can someone explain it to me...

S. Tiss
  • 139
  • 1
  • 9

1 Answers1

2

"2cfalse" is only added to the String pool in line 17, when you compare a to the literal "2cfalse".

The instance referenced by a prior to line 17 wasn't added to the String pool, so it's not the same instance as the "2cfalse" literal.

If you add a call to a.intern () just before line 17, the instance referenced by a will be added to the pool (since it wasn't already in the pool), and the condition in line 17 would evaluate to true.

If a String equal to "2cfalse" was already in the pool prior to calling a.intern(), you'd have to assign it back to a (i.e. a = a.intern();) in order for a to reference the instance stored in the pool.

String a = "";
a += 2;
a += 'c';
a += false; 
a.intern (); // or a = a.intern(); in case the pool already contains "2cfalse"
if ( a == "2cfalse") System.out.println("==");
if ( a.equals("2cfalse")) System.out.println("equals");

Output:

==
equals
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Thank you very much for your answer. Can you please explain why are the previous instances before line 17 not being added to the String Pool? – S. Tiss May 05 '21 at 05:27
  • @S.Tiss not every String instance is automatically added to the pool. I believe only instances of String literals and instances for which `intern()` was called are added to the pool. – Eran May 05 '21 at 05:30
  • 1
    @S.Tiss only literals will be added to the string pool by the JVM, other strings may be added by calling `intern()`. Note, however, that if you _constuct_ a string like you're doing with `"2cfalse"` your `==` case would fail even if the literal was already on the string pool. That's because new string objects are not on the pool by default, even if they have the same values as those on the pool. – Thomas May 05 '21 at 05:30
  • 1
    I'd add one additional piece of information for clarity: if `"2cfalse"` already was in the pool when `a.intern()` is called you'd need to assign the returned string or `==` would still fail. In the case above it works because the instance is put onto the pool before retrieving it via the literal. – Thomas May 05 '21 at 05:34
  • @Thomas that's correct – Eran May 05 '21 at 05:36
  • 1
    *compile-time constants* are added to the pool. So, `("" + 2 + 'c' + false) == "2cfalse"` will evaluate to `true`. Though, if you write the entire expression that way, it will get replaced by the compile time constant `true` at compile-time already, so still no string will be added to the pool at all. If you write `String s = "" + 2 + 'c' + false; boolean b = s == "2cfalse";`, `b` will be `true` and the string added to the pool but that just demonstrates that the *object identity* is more important than the pool. – Holger May 05 '21 at 08:37