池何时更改?

2022-09-03 01:14:33

我有两个问题:

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");
}
  • 为什么 和 指向同一个对象,而 和 则不指向 ?(没有使用关键字)。s1s2s1s3

  • 如果我从用户那里获得一个字符串并添加到上面的代码中,这些行:

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

    如果用户进入程序将打印,当用户输入另一个东西时程序输出。这是否意味着池会随着整个程序的执行而发生变化?优化器是否在编译时工作并继续在运行时工作xyzNot equalEqual


答案 1

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

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

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

但请注意,在JLS中,字符串常量池中可以和不能进入的细节故意保持模糊,因此不同的实现可能会以不同的方式进行优化。它指定了关于必须进入其中的某些规则,但不要依赖于这种行为在实现中保持一致。


答案 2

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

由于在Java中是,所以字符串类的任何方法都会返回一个新的String对象(虽然有一些例外 - 一个是方法)。因此,方法创建一个新字符串,该字符串转到,并且不添加到常量池中。StringImmutablesubstringconcat

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

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

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

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