Reputation: 918
According to my knowledge, we cannot use ==
operators to compare String
values in Java. So I wrote the following code:
public class Test {
public static void main(String[] args) {
String s1 = "My Computer";
String s2 = "My" + " Computer";
System.out.println(s1 == s2);
}
}
And I was expecting the result to be false
because these are two different objects having assigned different memory locations (please correct me in this regard if I am wrong ). But when I executed the code, the output was true
.
Then I changed the value of s2
as:
String str = "My";
String s2 = str + " Computer"; //instead of "My" + " Computer"
And then when I executed the code, the output was false
.
Now I cannot understand the difference in these two statements, although I have used +
(not the concat()
method) in both statements. Can anyone explain, please.
Upvotes: 0
Views: 148
Reputation: 49714
What trips you up is this part of the specification:
The String object is newly created (§12.5) unless the expression is a constant expression (§15.28).
So when you concatenate a string constant to another string constant, that counts as a constant expression and therefore will be evaluated at compile time and replaced with the string constant "My Computer".
You can verify this by running javap -c
on the compiled class.
public class Test {
public static void main(String[] args) {
String s1 = "My Computer";
String s2 = "My" + " Computer";
String s3 = "My";
String s4 = s3 + " Computer";
System.out.println(s1 == s2); //true
System.out.println(s1 == s4); //false
}
}
Which compiles to:
public static void main(java.lang.String[]);
Code:
// s1 = "My Computer"
0: ldc #2 // String My Computer
2: astore_1
// s2 = "My" + " Computer"
3: ldc #2 // String My Computer
5: astore_2
// s3 = "My"
6: ldc #3 // String My
8: astore_3
// s4 = s3 + " Computer"
9: new #4 // class java/lang/StringBuilder
12: dup
13: invokespecial #5 // Method java/lang/StringBuilder."<
init>":()V
16: aload_3
17: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: ldc #7 // String Computer
22: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: invokevirtual #8 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
28: astore 4
... the rest of the code omitted
As you can see, the first two assignments (to s1
and s2
) load exactly the same constant (#2
), and therefore use the same object. Whereas the assignment to s4
is not defined as a constant expression (even though a sufficiently clever compiler could figure it out, it is not allowed to), and therefore you get the whole "create a StringBuilder, append the strings to it, convert the result to a new string" process.
As an interesting aside, if in the code above you add the final
modifier to s3
, that makes s3 + " Computer"
a constant expression again, and both comparisons will print true
.
And as no doubt you already know, your code's correctness mustn't rely on all of this, but it's a fun thing to know.
Upvotes: 2
Reputation: 219
There is a silly error in your test cases.
String s2 = s1 + " Computer";
would assign s2
the string "My Computer Computer", not "My Computer".
For how to do String comparison Java, visit this link.
Why String is immutable in Java - an article explaining why instances of the String class in Java can not be modified. Read this for clarity.
Upvotes: 2
Reputation: 2090
Java uses a pool for String objects - it tries to be smart. This means that when the compiler can figure out that you actually have the same object, even the ==
on two seemingly different objects return true.
Nevertheless, it should be avoided to compare objects via ==
if you like to compare the content, as this only compares the object reference. For content comparison equals
should be used.
Upvotes: 2