String S1="He";
String S2="llow";
String S3="Hellow";
String S4="He"+"llow";
String S5=S1+S2;
System.out.println(S3==S4); // prints true
System.out.println(S5==S3); // prints false
System.out.println(S5==S4); // prints false
为什么S5
不是从常量池引用对象?
因为S3
和S4
在池中,这就是为什么在S3==S4
上给出真的
但是在S5==S3
& S5==S4
结果为false,表示S5不在池中。
答案 0 :(得分:5)
字符串s1
到s4
都是编译时常量。
编译器在编译期间计算"He" + "llow"
,并查询字符串池是否已经存在结果,如果不存在则将其放在那里。
但s1 + s2
的计算不是在编译时完成的,因此其结果不会被实现。为什么?因为从理论上讲,另一个线程可以更改s1
或s2
的值,所以当我们在代码中获得此指令时,它可能会将s2
设置为"foo"
,结果变为"Hefoo"
。
作为作者,您可能知道没有线程会这样做,并且这些都是局部变量,但是编译器没有。
如果您将定义更改为:
final String s1="He";
final String s2="llow";
final String s3="Hellow";
final String s4="He"+"llow";
final String s5=s1+s2;
然后,s5 == s3
的结果确实是true
!为什么?因为final
关键字让编译器知道这些字符串不会被替换,所以它们是这些变量的 final 值。因此它可以在编译时计算它并获取池中已有的结果。
答案 1 :(得分:2)
来自JLS
https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
由常量表达式计算的字符串(第15.28节)计算在 编译时间,然后将其视为文字。
在运行时通过串联计算的字符串是新创建的 因此不同。
对于String S4,你正在进行编译时连接,
String S4="He"+"llow";
因此,它指的是与S3相同的对象
但是,S1+S2
是运行时的串联,因此,它引用单独的String对象而不是S3,即使S1 + S2
和S3
有意义的等效 。
即(S1+S2).equals(S3)
将返回真实
您可以使用intern
方法
答案 2 :(得分:2)
因为在String S4="He"+"llow";
对象中创建了池,并且这是与S3="Hellow";
相同的编译时常量,它们在池中都是相同的对象,但在运行时在堆中创建S5
。
答案 3 :(得分:0)
连接的字符串文字输入到字符串池中。但是,由变量串联产生的字符串不是。这就是为什么S3等于S4而不是S5。它们不是指同一个对象。但是,(虽然我还没有对此进行测试)S5.equals(S4)应该返回true。
答案 4 :(得分:0)
System.out.println(S3==S4);//true
因为S4 = "He"+"llow";
由编译器优化并导致与" Hellow"相同的字符串。 共享与S3
,因此S4和S3具有相同的参考。
System.out.println(S5==S3);//false
因为S5
和S3是2个具有不同引用的不同对象。
System.out.println(S5==S4);//false
与以前一样。
比较对象时,通常需要比较内容(使用equals()
而不是地址/引用(使用==
)。
答案 5 :(得分:0)
通常,编译器实例化常量字符串 - 甚至是连接创建的字符串。这就是S3
和S4
是同一个对象的原因。
S5
在运行时被评估,这就是为什么它创建一个新的对象,不同(但等于)S4
。如果您自己将其放入字符串池中,您将再次获得与S4
相同的对象,因此S5.intern() == S4
将为真。
请注意,S5
与S4
不同,不能保证。更优化的编译器可以在编译时将其放入字符串池中。
答案 6 :(得分:-1)
比较java中的字符串使用equals
在java对象中==比较内存地址
字符串S5 = S1 + S2;
S1 + S2返回新的字符串对象
某些对象具有明显的记忆地址 你可以比较使用等于
的System.out.println(S5.equals(S4));
如果连接许多字符串对象,请使用StringBuilder 他们禁食并使用最少的记忆