StringBuffer和String池

时间:2013-04-03 12:40:28

标签: java

给出以下代码:

StringBuffer str2 = new StringBuffer(" I don't");
    StringBuffer str3 = str2.append(" get it.");
    if (str2 == str3)
    {
        System.out.println("Equal");
    }

我的讲师说,在这种情况下,str2str3都会引用同一个对象 字符串“我不明白”将被插入“字符串池”。

我认为我明白为什么str2str3现在将引用相同的对象,但为什么字符串“我不明白”。在str3分配发生时进入字符串池?

例如,如果我这样做:

 String s = "abcd";

然后我知道现在字符串“abcd”将被插入到“字符串池”中,如果它还没有存在。

我很想得到解释。

6 个答案:

答案 0 :(得分:5)

  

为什么字符串“我不明白”。进入字符串池。

"I don't get it."字符串无法进入实习池。

验证方法如下:

StringBuffer str2 = new StringBuffer(" I don't");
StringBuffer str3 = str2.append(" get it.");
String str = new String(str3.toString());
if (str == str.intern()) {
    System.out.println("It was not interned before"); // <<== This is printed
} else {
    System.out.println("It was interned before");
}

如果String的内容被实习,则intern()的调用将返回不同的(“规范”)对象。如您所见,上面返回相同的对象,这意味着您调用intern()的对象刚刚成为“规范”对象(即已被实习)。

另一方面,如果您删除append,则会得到不同的结果:

StringBuffer str2 = new StringBuffer(" I don't");
StringBuffer str3 = str2;
String str = new String(str3.toString());
if (str == str.intern()) {
    System.out.println("It was not interned before"); // <<== This is printed
} else {
    System.out.println("It was interned before");
}

现在str3内的字符串为" I don't"。它的副本已经被实现,因为它与创建str2时使用的字符串常量相同。

您可以并排运行the firstthe second程序,以便自己查看差异。

str2 == str3true的原因与字符串池无关(俚语是"string interning")。这两者是相同的,因为StringBuffer.append返回调用append的对象,即str2。你没有第二个对象 - 只有一个StringBuffer有两个引用它。 StringBuffer的内容是" I don't"" get it."字符串的串联。

答案 1 :(得分:2)

你缺少的是string literal的概念。

在以下情况下添加到池中的字符串:

  • 它被定义为文字。
  • 你在它上面调用方法实习生。

并且尚未进入池中。

在您的示例中,您将字符串文字放入StringBuffer类型的对象中。要从该对象检索字符串,您必须调用toString()。要将结果添加到字符串池,您必须另外在该字符串上调用intern()

证明我们可以进行简单的测试。

String s1 = "This is a simple test";
String s2 = "This is a simple test";

System.out.println(s1 == s2);

StringBuffer sb1 = new StringBuffer(s1);
StringBuffer sb2 = new StringBuffer(s2);

String result1 = sb1.toString();
String result2 = sb2.toString();

System.out.println(result1 == result2);

String internedResult1 = result1.intern();
String internedResult2 = result2.intern();

System.out.println(internedResult1 == internedResult2);

代码输出将是:

  

是的   假
  真

答案 2 :(得分:0)

您要比较StringBuffer个对象,而不是(实习)String。如果您查看StringBuffer.append( String )实施,则会注意到它以return this;结尾,因此您的str2str3是同一个对象。

public synchronized StringBuffer append(String str) {
super.append(str);
    return this;
}

编辑:当您的代码中的两个字符串文字被实习(在“字符串池”中)时,组合字符串“我不明白”将不会被实习。通过检查StringBuffer代码(在内部将组合表示为char[]数组,这一点很清楚。)

干杯,

答案 3 :(得分:0)

StringBuffer#append(StringBuffer sb)

  

将指定的StringBuffer追加到此序列。的人物   StringBuffer参数按顺序附加到。的内容   这个StringBuffer,增加了这个StringBuffer的长度   论证的长度。如果sb为null,则四个字符为“null”   附加到此StringBuffer。

     

设n是旧字符序列的长度,包含的字符序列   在执行append方法之前的StringBuffer中。然后   新字符序列中索引k处的字符等于   如果k小于,则旧字符序列中索引k处的字符   N;否则,它等于索引k-n中的字符   论证sb。

     

此方法在此(目标)对象上同步但不同步   同步源(sb)。

您将得到真实,因为两者的引用相同。

答案 4 :(得分:0)

似乎有些混乱。 StringBuffer是可变的,这意味着它的内容可以被修改。 StringBuffer中的方法append()将一个String附加到缓冲区内的字符串并返回实例。这一行:

StringBuffer str3 = str2.append(" get it.");

将具有与以下相同的实际结果:

str2.append(" get it.");
StringBuffer str3 = str2;

换句话说,str3和str2指向同一个对象。因为你附加了字符串文字“得到它”。为了“我不”,这个StringBuffer将包含“我不明白。”。

答案 5 :(得分:0)

  

为什么字符串“我不明白”。 str3分配发生时进入字符串池?

没有。你的讲师在这一点上是错误的。唯一可能发生的方法是StringBuffer调用String.intern(),但它没有,或者至少没有指定它。