public class First
{
public static void main(String[] args)
{
String str1="Hello ",str2="World",str3="Hello World";
System.out.println(str3==("Hello "+"World")); //Prints true
System.out.println(str3==("Hello "+str2)); //Prints false
}
}
上述原因在JLS中给出 -
•由常量表达式计算的字符串(第15.28节)计算在 编译时间,然后将其视为文字。
•在运行时通过串联计算的字符串是新创建的 因此不同。
我想问的是 - 为什么在运行时计算的字符串与在编译时计算的字符串不同? 是因为内存分配,一个是在堆中分配内存而另一个是在String池中还是有其他原因?请澄清。
答案 0 :(得分:2)
编译器无法知道str2
包含的内容,因为当您使用" Hello&#34连接它时,必须执行代码才能知道str2
的内容; (它可以进行一些优化并内联它,因为它没有改变,但它没有做到)。
想象一个更复杂的场景,其中str2
是用户输入的内容。即使用户输入了" World"编译器无法知道这一点。
因此,它无法使用与str3 == "Hello World"
分配给"Hello World"
并在第一次比较中使用的常量池中的相同str3
来执行比较StringBuilder
。
因此编译器将使用String
生成连接,并最终创建另一个值为Hello World
的{{1}},因此身份比较将失败,因为一个对象是来自常量池,另一个是刚刚创建的池。
答案 1 :(得分:1)
在比较equals
而不是Objects
运算符时,您应该使用==
。
答案 2 :(得分:0)
字符串在Java中是不可变的。因此,当您连接两个字符串时,将在运行时创建第三个字符串以表示连接值。所以使用==返回false,因为两个参数都指向String对象的不同实例。
对于编译时方案,由于编译器优化,已经创建了连接字符串,并且在运行时,==的boht参数由相同的实例表示。因此,==返回true,因为两个参数都指向同一个实例(引用)。
答案 3 :(得分:0)
编译器认识到常量不会改变,如果您使用+运算符,则将它们串联在已编译的代码中。
这就是为什么在第一种情况下它将以str3==("HelloWorld")
运行执行的原因,因为字符串池中已经存在“ Helloworld”文字,它们都将指向字符串池中的同一位置,并显示true。
在str3==("Hello"+str2)
的情况下,编译器不会检查str2是否包含World
,它将视为具有任何值的变量,因此在运行时,它们将创建一个新的指向与字符串池中的HelloWorld
不同的str3
的字符串变量,因此它将显示false。