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
}
这导致
true
true
true
false
false
false
true
表达式e==a
为true意味着相同的引用。那么为什么最后一个表达式是真的但是第四个到最后一个,即c== "Hel"+a
是假的?
答案 0 :(得分:16)
表达式
"Hel" + a
不是编译时间常量。实际上,它编译为:
new StringBuilder().append("Hel").append(a).toString()
(或类似)在运行时创建一个新的String对象。
但是,因为e
是最终的,编译器可以确定"Hel"
和e
的值的连接是一个常量值实习生就这样。
答案 1 :(得分:10)
所有这些字符串都是在运行时计算的,这就是它们不同的原因
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?
这个在编译期间计算,因为e是最终的:
System.out.println(c=="Hel"+e); //this is true
如果您将代码更改为:
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?
所有这些都会产生真正的
答案 2 :(得分:5)
Java compiler(javac
)会将code in Java翻译为由byte code执行的JVM。
它还为您做了一些优化。您可以使用带有javap
参数
-c
实用程序检查生成的字节代码
与最终字符串连接
c==a
是正确的,因为c
是final
以下是此代码段的字节代码(仅限上次比较):
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
}
如您所见,java编译器已将“Hel”与“lo”合并,只是将两个字符串leterals“Hello”进行比较。 Java默认情况下实习字符串文字 - 这就是它返回true的原因
与非最终字符串连接
如果要将字符串文字与非最终字符串变量连接起来,则字节代码将不同:
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
}
这里我们比较显然返回另一个对象的java/lang/StringBuilder.toString:()Ljava/lang/String;
方法的结果 - 它等于“Hello”值而不是引用
答案 3 :(得分:1)
即使您使用intern()
方法,您仍然需要记住==
按引用进行比较而不是值。
所以在
的情况下System.out.println(c=="Hel"+a);
System.out.println(c=="Hel"+d);
System.out.println(c=="Hel"+b);
"Hel" + a
或"Hel" + d
或"Hel" + b
在内存中的新引用不会等于c
的引用。
在最后一种情况下,因为字符串值是final,所以评估发生在编译时而不是运行时作为优化,因为它永远不会改变。此外,如果您在考虑定义字符串文字时,Java会在内部实现它们。