1

Today while working with String's i have encountered a behavior i don't know before. I'm not able to understand what's happening internally.

    public String returnVal(){
         return "5";
     }
 String s1 = "abcd5";
 String s2 = "abcd"+"5";

 String s3 = "abcd5";
 String s4 = "abcd"+returnVal();

 System.out.println(s1 == s2);
 System.out.println(s1.equals(s2));
 System.out.println(s3 == s4);
 System.out.println(s3.equals(s4));

My expectation is printing "true" from all s.o.p's but s3 == s4 is false, why?

SaiKiran V
  • 23
  • 2
  • 1
    These duplicates don't answer OP's question. – Andy Turner Jul 04 '16 at 10:03
  • 2
    Mobile app edited instead of adding comment... I previously said that `"abcd"+"5"` is a compile time constant, and is identical to `"abcd5"`, so that is the value used from the string constant pool; whereas `"abcd"+returnVal()` is not compile-time constant, so a new string is created at runtime. – Andy Turner Jul 04 '16 at 10:06
  • Thanks @AndyTurner So the "abcd"+returnVal() object is created in the heap instead of using from scp just like when new operator is used. – SaiKiran V Jul 04 '16 at 10:15
  • 2
    @khelwood, Jens - the duplicates are not answering my question. it is not a question about == vs equals() . – SaiKiran V Jul 04 '16 at 10:17
  • Does this duplicate answer the question? http://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java. There are many more. :-) I don’t see how it’s not a question of == versus .equals(). Once you’ve understood that part, I believe you can set your expectations right for OP’s code. – Ole V.V. Jul 05 '16 at 15:27
  • Once I was teacbhing, emphasizing the use of .equals() between Strings, I told my students that Java’s behaviour of _sometimes_ evaluating == to true was destructive for any teaching effort. :-) Then I showed them an example that looked pretty much the same as the code in the question. – Ole V.V. Jul 05 '16 at 15:31

2 Answers2

1

My expectation is printing "true" from all s.o.p's but s3 == s4 is false, why?

The compiler can do constant expression inlining. This means that

String s1 = "abcd5";
String s2 = "abcd"+"5";
final String five = "5"; // final reference
String sa = "abcd" + five;

are all the same (except five) and the compiler can simplify all these expressions to "abcd5"

However, if the compiler cannot optimise the expression, the operation is performed at runtime and a new String is created. This new String is not a constant which is places in the String literal pool (as it is not a literal in byte code)

 String s4 = "abcd" + returnVal(); //  not inlined by the compiler.
 String f5 = "5";  // not a final reference.
 String sb = "abcd" + f5; // evaluated at runtime

These create new strings every time they are run (as well as new StringBuilder and char[]s)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
0

You have stumbled across the intricacies of how the Java compiler optimizes String.

Suppose I have this program:

String a = "abc";
String b = "abc";

Here the compiler can initialize a and b to the same String instance. This entails that a == b and a.equals(b).

Here we also get the same behaviour:

String a = "abc";
String b = "ab" + "c";

This is because "ab" + "c" can be evaluated at compile-time to just "abc", which in turn can share an instance with a.

This technique is not possible with expressions that call functions:

String a = "abc";
String b = "ab" + functionThatReturnsC();

This is because functionThatReturnsC could have side-effects which cannot be resolved at compile-time.

Your case of returnVal is interesting. Since it is constant, it could be inlined, in which case the compile-time instance sharing could be applied. It seems the compiler implementer decided not to support this.

This issue exposes a weakness of Java. Since we cannot override =, programmers cannot implement custom value-types. Therefore, you should always use equals or Objects.equals to ensure consistent behaviour.

Note that these optimizations may differ between compilers.

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245