4

I have this code in Java :

    String s0="ab";
    String s1="bc";
    String s2="abbc";
    String s3="ab"+"bc";
    String s=s0+s1;

When i try to compare s & s2 using if(s==s2), it returns false,
But on comparing s2 & s3 using, if (s2==s3) returns true.

Why is the output not same in both the cases?

Suhail
  • 85
  • 6
  • 5
    I'm assuming you know the difference between `.equals()` and `==` when it comes to strings, right? – arshajii Dec 05 '13 at 16:36
  • This question has been answered many time on this website. Just do a search and you'll find your answer. – TheEwook Dec 05 '13 at 16:38
  • Java doesn't have a special `==` operator for strings, it only compares if it's the _same_ string that both variables refer to, not if the contents are the same. – Joachim Isaksson Dec 05 '13 at 16:38
  • Yes, i know.How is it related to this kind of behavior? – Suhail Dec 05 '13 at 16:39
  • @Suhail The compiler combines "ab"+"bc" into "abbc" at compile time. The compiler then combines identical constant strings to be references to the same string object. – Joachim Isaksson Dec 05 '13 at 16:41
  • 1
    @JonSkeet I don't think this is a duplicate of that. The OP is asking a more meaningful question. – arshajii Dec 05 '13 at 16:42
  • @arshajii: We don't really know - the question isn't clear as to whether the OP expects == to perform value equality, or whether it's a constant folding question. – Jon Skeet Dec 05 '13 at 16:53
  • I was going to go hunt for a question specific to the constant folding, but I noticed that the top answer for "How do I compare strings in Java?" already covered it anyway. – Dennis Meng Dec 05 '13 at 18:11

2 Answers2

7

String s3 is being assigned to a compile-time constant which is exactly equivalent to "abbc". Hence, s2==s3 compares two identical string literals, which results in true since these literals are interned.

s0+s1 is not a compile time constant, so a new string object is produced. Therefore, s==s2 returns false.


In terms of byte code,

String s3="ab"+"bc";

becomes

LDC "abbc"
ASTORE 1

Notice that "abbc" is used directly.


Lastly, if you declare s0 and s1 to be final, then s0+s1 would be a constant expression and s==s2 would be true.

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • As you said,in case of `s=s0+s1`,new String object will be created.I agree but finally `s` will refer to the same string object which is already there in String pool.Isn't it ? – Suhail Dec 05 '13 at 16:48
  • @Suhail No. If you're creating a new object, you're creating a new object. There's no referring to an older object instead (unless there's interning, but that's not happening here). – Dennis Meng Dec 05 '13 at 18:29
  • @DennisMeng As per my knowledge, String literals are always interned. – Suhail Dec 05 '13 at 18:59
  • @Suhail No, `s0+s1` explicitly creates a *new* (i.e. not in the string pool) instance unless `s0` and `s1` are `final`, as I've described. – arshajii Dec 05 '13 at 19:04
  • @DennisMeng As per my knowledge, `String` literals are always interned.In the above code `String s=s0+s1;` ,s should evaluate to `String s=abbc` at runtime but it is showing behavior like `new String("abbc")`.Why is it so ? – Suhail Dec 05 '13 at 19:05
  • Is there any reference or document where i can read more about this kind of behavior. Thank You – Suhail Dec 05 '13 at 19:07
  • @Suhail String *literals* are interned, yes. And `s0+s1` does evaluate to `"abbc"` at runtime. However it's still not the same instance as what's in the string pool. – arshajii Dec 05 '13 at 19:07
  • @arshajii The runtime environment receives `String s2="abbc";`. `String s3="abbc";` and `String s=s0+s1;` where s evaluates to `abbc`. So at runtime `s2,s3 & s` all have the same value `abbc`. For `s2 and s3` runtime environment returns the reference of `abbc` from string pool. Then why can't it do the same for `s object`? Why it creates a new object on heap ? – Suhail Dec 05 '13 at 19:20
  • @Suhail For that last point, I think I saw that too before; something about not knowing with 100% certainty at compile-time that `s0` and `s1` have those values when that line is executed. The last part of this answer brings up how you would basically tell the compiler "no worries, this variable won't change" so that it knows it can still do constant folding. – Dennis Meng Dec 05 '13 at 19:38
1

The == operator compares the pointers of the objects, not the objects themselves. To compare string values you should use either equals(..) or equalsIgnoreCase(..), whichever is appropriate.

The strings s2 and s3 are probably comparing as equal because they are being interned behind the scenes. Interning is taking commonly used strings, holding them in (I think) PermGen and just using a single reference for that string. This is useful when you have a lot of strings with the same value and works because strings are non-mutable. Whenever you add something to a string a new string is created.

disrvptor
  • 1,592
  • 12
  • 23