运行时串联和java中编译时的区别

时间:2015-07-09 05:31:14

标签: java string heap

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池中还是有其他原因?请澄清。

4 个答案:

答案 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。