3
String s1 = "String";
String s2 = "String" + "";
String s3 = "" + s2;
System.out.println (s1 == s2);
System.out.println (s2 == s3);
System.out.println (s1 == s3);

true 
false 
false

Why do I get false values ? Shouldn't be s3 variable in String pool ? It's the same. It seems I don't understand String pool fully.

Imugi
  • 161
  • 1
  • 3
  • 13
  • 1
    *Shouldn't be s3 variable in String pool* -> @Simze - No it is not dupe of that question – TheLostMind Feb 17 '16 at 12:59
  • define the strings as 'final' – Srini Feb 17 '16 at 13:07
  • 4
    Why has this question been downvoted so much? It's actually not a bad question and while not the prettiest, it is quite clear what the OP is asking. –  Feb 17 '16 at 13:07
  • @DanK - Thats the problem.. Any time people see `==` in a String question, they close their eyes and DV + CV it :P – TheLostMind Feb 17 '16 at 13:08
  • 1
    I agree. It's a well-posed question and the answer is not obvious. – Bathsheba Feb 17 '16 at 13:12
  • 2
    @Bathsheba - I know that there are dupes for this particular question out there.. But this one is incorrectly being closed as a dup of `==` vs `equals()`. Reopened it – TheLostMind Feb 17 '16 at 13:13

2 Answers2

6

Since your Strings are not marked final, they will be created at runtime using StringBuilder (when you use + operation and concatenate Strings) and will NOT go into the String constants pool. If you want the Strings to go into StringPool when the class is loaded (just like literals), you should mark them as final and thus making them constants.

Like this :

public static void main(String[] args) {
    final String s1 = "String";  // "String" will go into the constants pool even without `final` here. 
    final String s2 = "String" + ""; // Goes into the String constants pool now.
    final String s3 = "" + s2; // Goes into the String constants pool now.
    System.out.println (s1 == s2);
    System.out.println (s2 == s3);
    System.out.println (s1 == s3);
}

O/P :

true
true
true
TheLostMind
  • 35,966
  • 12
  • 68
  • 104
0

The problem is that "" + s2 is not a constant expression (see the corresponding section of the JLS). Only constant expressions of type String are required to be interned, and although it is not required that non-constant expressions are not interned, the JVM doesn't.

If you write:

String s1 = "String";
final String s2 = "String" + "";
String s3 = "" + s2;
System.out.println (s1 == s2);
System.out.println (s2 == s3);
System.out.println (s1 == s3);

then "" + s2" is a constant expression and the result of your snippet will be

true
true
true
Hoopje
  • 12,677
  • 8
  • 34
  • 50
  • Well... maybe picking nits but the spec says this is a constant expression; `Simple names (§6.5.6.1) that refer to constant variables (§4.12.4).` and [§4.12.4](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4) defines the constant type "effectively final" as (the simplified version at the end) `a local variable or parameter that is declared final in a valid program becomes effectively final if the final modifier is removed.`. In other words, the `final` shouldn't be required as far as I see to make s3 a constant expression. – Joachim Isaksson Feb 17 '16 at 13:58
  • @JoachimIsaksson There is a difference between *final* and *effectively final*. As the JLS specifies: "Three kinds of variable are implicitly declared final: a field of an interface (§9.3), a local variable which is a resource of a try-with-resources statement (§14.20.3), and an exception parameter of a multi-catch clause (§14.20)." *Effectively final* is only defined afterwards. – Hoopje Feb 17 '16 at 14:26