4

Can anyone explain this strange behavior of Strings?

Here's my code:

String s2 = "hello";
String s4 = "hello"+"hello";
String s6 = "hello"+ s2;

System.out.println("hellohello" == s4);
System.out.println("hellohello" == s6);

System.out.println(s4);
System.out.println(s6);

The output is:

true
false
hellohello
hellohello
Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
Hitesh
  • 703
  • 1
  • 9
  • 14
  • output is correct, as you can simply proove. – sina72 Jul 02 '14 at 08:30
  • Here's your assignment: Compile with `javac -XD-printflat -d ` and see what the output is. Hint: This "oddity" is **not** caused by the String pool, although the pool is still involved. Bonus points for seeing what happens if you add `final` to the variable declarations – awksp Jul 02 '14 at 08:30
  • Why do you find it "strange"? – Peter Petrik Jul 02 '14 at 08:31
  • 1
    do you know about String.equals ? – Scary Wombat Jul 02 '14 at 08:31
  • 2
    possible duplicate of [whats the difference between ".equals and =="](http://stackoverflow.com/questions/1643067/whats-the-difference-between-equals-and) – Dubas Jul 02 '14 at 08:33

4 Answers4

6

You need to be aware of the difference between str.equals(other) and str == other. The former checks if two strings have the same content. The latter checks if they are the same object. "hello" + "hello" and "hellohello" can be optimised to be the same string at the compilation time. "hello" + s2 will be computed at runtime, and thus will be a new object distinct from "hellohello", even if its contents are the same.

EDIT: I just noticed your title - together with user3580294's comments, it seems you should already know that. If so, then the only question that might remain is why is one recognised as constant and the other isn't. As some commenters suggest, making s2 final will change the behaviour, since the compiler can then trust that s2 is constant in the same way "hello" is, and can resolve "hello" + s2 at compilation time.

Amadan
  • 191,408
  • 23
  • 240
  • 301
5
String s2 = "hello";
String s4 = "hello" + "hello"; // both "hello"s are added and s4 is resolved to "hellohello" during compile time (and will be in String pool)
String s6 = "hello"+ s2; // s6 is resolved during runtime and will be on heap (don't apply Escape analysis here)

So,

System.out.println("hellohello" == s4); // true
System.out.println("hellohello" == s6);  // false
PurkkaKoodari
  • 6,703
  • 6
  • 37
  • 58
TheLostMind
  • 35,966
  • 12
  • 68
  • 104
5

"hello" + s2 works like this:

More info:

Community
  • 1
  • 1
Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
2

String s4 is interned and reference to this string and to "hellohello" is the same. Because of that you get true on the line:

System.out.println("hellohello" == s4);

String s6 is not interned, it depends on a variable s2. And references to "hellohello" and to string s6 are not equal. Because of that you get false on the line:

System.out.println("hellohello" == s6);

But if you declare s2 as final, which makes s2 constant, you will get true instead of false on the line System.out.println("hellohello" == s6);, because now compiler can intern the string s6, as it depends on constant values, and the references to "hellohello" and to s6 will be equal to each other.