Reputation: 2583
public static void main(String[] args) {
String a = new String("lo").intern();
final String d = a.intern();
String b = "lo";
final String e = "lo";
String c = "Hello";
System.out.println(b==a);//true
System.out.println(d==a);//true
System.out.println(e==a);//true
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
System.out.println(c=="Hel"+e); //this is true
}
This results in
true
true
true
false
false
false
true
The expression e==a
is true implies same reference. So why the last expression is true but the 4th to last ie c== "Hel"+a
is false?
Upvotes: 18
Views: 697
Reputation: 424983
The expression
"Hel" + a
Is not a compile time constant. Actually, it compiles to:
new StringBuilder().append("Hel").append(a).toString()
(or similar) which creates a new String object at runtime.
However, because e
is final, the compiler can determine that the concatenation of "Hel"
and e
's value is a constant value, and so interns it.
Upvotes: 16
Reputation: 4586
Java compiler (javac
) translates your code in Java to byte code which is executed by the JVM.
It also does some optimizations for you. You can check the generated byte code using javap
utility with -c
parameter
Concatenation with final String
c==a
is true because c
is final
Here is the byte code for this snippet (last comparison only):
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String Hello
2: astore_2
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_2
7: ldc #2; //String Hello
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
}
As you see the java compiler has merged the "Hel" with "lo" and just comparing two string leterals "Hello". Java interns string literals by default - that's why it returns true
Concatenation with non-final String
If you are concatenating the string literal with non-final String variable, the byte code will be different:
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String lo
2: astore_1
3: ldc #3; //String Hello
5: astore_2
6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_2
10: new #5; //class java/lang/StringBuilder
13: dup
14: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
17: ldc #7; //String Hel
19: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: if_acmpne 36
32: iconst_1
33: goto 37
36: iconst_0
37: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
40: return
}
Here we are comparing the result of java/lang/StringBuilder.toString:()Ljava/lang/String;
method which obviously returns another object - it is equal to "Hello" by value but not by reference
You can find more details on comparing strings in this stackoverflow question
Upvotes: 5
Reputation: 9237
Even though you are using intern()
method, you have to still remember that ==
compares by reference and not value.
So in the cases of
System.out.println(c=="Hel"+a);
System.out.println(c=="Hel"+d);
System.out.println(c=="Hel"+b);
"Hel" + a
or "Hel" + d
or "Hel" + b
will have a new reference in memory that is not equal to that of c
.
in the final case since the string value is final, the evaluation happens at compile time instead of runtime as optimization since it will never change. Also if you are thinking when you define string literal, Java internally interns them.
Upvotes: 1
Reputation: 24146
all these strings are calculated in runtime, this is why they are different
System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
this one calculated during compile time, because e is final:
System.out.println(c=="Hel"+e); //this is true
if you change code to this:
System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
System.out.println(c==("Hel"+d).intern()); //why is this false?
System.out.println(c==("Hel"+b).intern()); //why is this false?
all of them will produce true
Upvotes: 10