Java中新String("X")和新String("X")+ new String("Y")之间字符串初始化的差异

Leb*_*cca 9 java

public static void main(String[] args) {
    String s1 = new String("aa");
    s1.intern();
    String s2 = "aa";
    System.out.println(s1 == s2);

    //wrong in JDK1.6 but true in JDK1.8
    String str1 = new String("str") + new String("01");
    str1.intern();
    String str2 = "str01";
    System.out.println(str1 == str2);

}
Run Code Online (Sandbox Code Playgroud)

我用JDK1.8运行上面的代码,我认为结果会得到两个"falses",因为在我看来,很明显s1和str1位于堆中,而s2和str2是在字符串中实现的游泳池,但我得到了"假"和"真实".问题来了:是什么导致"真实"?


以上是原始问题.现在要确定这个问题远不是这些被称为重复的问题,我想谈谈我的新发现:代码的第二部分使用JDK1.6获得"错误"结果,而使用JDK1.8获得"真实"结果.一些博客称,在JDK1.7发布后,intern()的行为发生了变化.

如果池不包含与此String对象相等的字符串,则此String对象将不会添加到池中,而是将对此String对象的引用添加到池中.这意味着池中的引用将被分配给位于其他位置的字符串对象(如堆),并且下一次文本字符串的初始化等于早期的字符串对象也将被分配给字符串对象.这正好描述了代码part2关于"真实"结果.

这个理论确实可以用来解释上面代码的结果.但很明显,该理论不属于intern()doc所包含的内容,这在JDK6/8 API中几乎相同.


现在的问题是:对JDK1.6和JDK 1.8中相同代码的不同结果有没有更好的解释?我上面提到的理论究竟是真正发生的吗?

Max*_*mer 20

首先,让我们看一下Java文档String.intern():

调用实习方法时,如果池已经包含等于此字符串对象的字符串(由equals(Object)方法确定),则返回池中的字符串.否则,将此String对象添加到池中,并返回对此String对象的引用.

然后让我们看看你的代码:

    final String s1 = new String("aa");
    s1.intern();
    final String s2 = "aa";
    System.out.println(s1 == s2);
Run Code Online (Sandbox Code Playgroud)

在这里创建3个 String对象.该字符串文字 "aa",它被添加到字符串池中new String("aa"),这是一个复制的构造"aa",但它是一个不同的实例,第二个字符串文字 "aa",它是取自一次(所以它是相同的实例作为第一个"aa") .当你调用时intern(),String池已经有一个String等于s1("aa"它是从它构造的文字),所以"aa"返回,但你不使用它并s1保持不同的实例.s1 == s2就是这样false.

    final String str1 = new String("str")+new String("01");
    str1.intern();
    final String str2 = "str01";
    System.out.println(str1 == str2);
Run Code Online (Sandbox Code Playgroud)

在这里创建6个 String对象.文字"str""01",放入池中.然后从这些文字创建两个副本.然后是这两个字符串的串联,这将是str1.这种拼接不放入池中立即,但它会被放入池中,当你调用intern()str1,所以str1本身现在是在游泳池.因此,当您创建str2String文字时 "str01",它将从池中获取,因此与实例相同str1.

  • @cppbeginner谢谢,我编辑了我的答案! (2认同)
  • 据我所知,第二个'println`输出是真还是假是未指定的.字符串常量""str01"`可以在`str1.intern()`置于"str01"之前或之后构造到池中. (2认同)
  • 第二种情况的结果取决于您选择的字符串.如果你选择一个由引导程序实例化的字符串,那么它将打印`false`.例如,请参阅:https://ideone.com/0OZOtC (2认同)