15
public static void main(String[] args) {
    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);
    String str2 = new StringBuffer("ja").append("va").toString();
    System.out.println(str2.intern() == str2);
}

结果:

 true
 false   

第一个打印true,第二个打印false。为什么结果不一样?

4

4 回答 4

20

行为上的差异与StringBuilder和之间的差异无关StringBuffer

String#intern()它返回的状态的 javadoc

当调用 intern 方法时,如果池中已经包含一个与String该方法确定的对象相等equals(Object) 的字符串,则返回池中的字符串。否则,将此 String对象添加到池中并返回对该对象的引用String

String创建自

String str2 = new StringBuffer("ja").append("va").toString();

是全新的String,不属于泳池。

为了

str2.intern() == str2

要返回falseintern()调用必须返回不同的参考值,即。已经在游泳池里String "java"

在第一次比较中, “计算机软件”在调用之前String不在字符串池中。因此返回与存储在. 引用相等因此返回。intern()intern()str2str2 == str2true

于 2015-08-14T01:38:55.090 回答
5

Because your assignments don't re-read from the intern pool and Java String(s) are immutable. Consider

String str1 = new StringBuilder("计算机").append("软件").toString();
String str1a = new String(str1); // <-- refers to a different String 
str1 = str1.intern();
str1a = str1a.intern();
System.out.println(str1a == str1);
String str2 = new StringBuffer("ja").append("va").toString();
String str2a = new String(str2); // <-- refers to a different String 
str2 = str2.intern();
str2a = str2a.intern();
System.out.println(str2a == str2);

The output is (as you might expect)

true
true
于 2015-08-14T01:37:10.767 回答
1

之前提到了很多关于池的答案,并用 Oracle 链接文档进行了非常清楚的解释。

我只是想指出我们在调试代码时可以检查的方式。

    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);//the str1.intern() returns the same memory address the str1
    String str2 = new StringBuffer("ja").append("va").toString();
    System.out.println(str2.intern() == str2);//the str2.intern() does not return the same memory address the str2

您可以使用任何 IDE 和调试来检查 str1 和 str1.intern()/str2 和 str2.intern() 的实际地址。

于 2015-08-14T01:59:37.767 回答
0

让我添加一些更有趣的东西:

  1. OpenJDK 8 是真的,真的;
  2. Oracle JDK 6 是真的,是的;

所以我认为正确的答案是:

不同供应商的 jvm 或 jvm 版本可能有不同的实现(语言规范不强制执行)

在 Oracle JDK 8(我猜你使用)中: 字符串“java”已经在池中(由 java.lang.Version#laucher_name 加载)并且字符串池只存储引用,而不是对象。

但是在 OpenJDK 中 laucher_name 是 "openJDK";在 Oracle JDK 6 及以下版本中,字符串池会将字符串对象复制到其自身

于 2018-10-15T14:07:58.747 回答