【问题标题】:When does the pool change?泳池什么时候换?
【发布时间】:2013-01-05 00:55:57
【问题描述】:

我有两个问题:

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中继续工作?

【问题讨论】:

    标签: java string pool


    【解决方案1】:

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

    由于Java中的StringImmutable,所以字符串类的任何方法都会返回一个新的String对象(不过也有一些例外——一个是substring方法)。因此,concat 方法创建了一个新字符串,该字符串进入 Heap,并且不会添加到常量池中。

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

    注意第二个字符串中的连接操作:-

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

    在编译时求值,已知结果与第一个字符串相同,并在常量池中输入一个条目。

    【讨论】:

      【解决方案2】:

      有时(当编译器很明显 String 的值在运行时是什么时)编译器使用字符串池,在其他情况下则不使用。

      其实你的代码不应该依赖于使用或不使用池的事实。

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

      【讨论】:

        【解决方案3】:

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

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-25
          • 1970-01-01
          • 2011-09-28
          • 1970-01-01
          相关资源
          最近更新 更多