游泳池什么时候改变?

我有两个问题:

public static void main(String[] args) { String s1 = "bla"; String s2 = "b" +"l" + "a"; String s3 = "b".concat("l").concat("a"); if(s1 == s2) System.out.println("Equal"); else System.out.println("Not equal"); if(s1 == s3) System.out.println("Equal"); else System.out.println("Not equal"); } 
  • 为什么s1s2指向同一个对象,而s1s3不指向? ( 没有使用new关键字 )。

  • 如果我从用户那里得到一个字符串并将以下代码添加到上面的代码中:

     BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); String name=in.readLine(); if(name.equals("test")) s1 = s1 + "xyz"; 

    如果用户输入xyz ,程序将打印Not equal ,当用户输入另一个程序时,程序输出Equal 。 这是否意味着池通过执行整个程序而改变? 优化程序是否在编译时工作继续在runtime

为什么s1和s2指向同一个对象,而s1和s3不指向? (没有使用新关键字)。

因为连接发生在编译时,因此完成的字符串在常量池中与第一个示例中相同。 这是编译器“已知”的特殊情况。 它的确意味着长串,以这种方式连接多行,仍然可以获得与简单字符串常量相同的性能改进。

在第二个示例中,您在运行时执行计算,因此它不会成为常量池的一部分。

但请注意,在JLS中,有意和无法进入字符串常量池的细节有意留下模糊,因此不同的实现可能以不同的方式进行优化。 它指定了必须遵循的某些规则,但不依赖于这种行为在各实现之间保持一致。

为什么s1和s2指向同一个对象,而s1和s3不指向? (没有使用新关键字)。

由于Java中的StringImmutable ,因此字符串类的任何方法都将返回一个新的String对象(虽然有一些例外 – 一个是substring方法)。 因此, concat方法创建一个新的字符串,该字符串将转到Heap ,而不会添加到常量池中。

s1s2情况而言,两个字符串在编译时都是已知的,因此它们是相同的字符串文字。

请注意第二个字符串中的串联操作 : –

 String s2 = "b" +"l" + "a"; 

在编译时进行求值,并且已知结果与第一个字符串相同,并且对常量池进行一个输入。

有时(当编译器显然字符串的值将在运行时是什么时)编译器使用字符串池,在其他情况下它不会。

实际上,您的代码不应该依赖于使用或不使用池的事实。

你不能总是运行main,所以如果你想看看你的String是否从池中使用,你可以用javap反编译代码,列表相对不言自明。