有关运行时常量池或堆中的String的一些问题?

时间:2019-07-19 04:50:25

标签: java string jvm

使用JDK1.8

//create string s1
String s1 = new String("1")+new String("1");

//native method, put s1 into string constant pool
s1.intern();

//create variable s2  
String s2 = "11";

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

在此代码中将输出true,但是如果用以下代码替换第一行

String s1 = new String("11")+new String("");

它将输出false

现在我的疑问是:
当第一个代码运行时,堆和池中发生了什么?和代码intern

最好向我描述每一步在堆和池之间如何变化,谢谢

2 个答案:

答案 0 :(得分:1)

您应该仔细阅读the documentation of s1.intern()

  

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

由于合同是关于方法将返回的内容,因此您不应忽略方法调用的返回值。

您关于s1.intern();将“将s1放入字符串常量池”的假设是错误的。该方法将返回包含在常量池中的字符串,如果没有相同内容的字符串,则该可能是现在已添加到池中的相同字符串以前。

因此,在您的第一个测试中,您展示了添加到池中的字符串的特定于实现的行为,因为以前没有字符串具有相同的内容。

相反,在第二个测试中,可以保证不会将字符串添加到池中。随着文档的继续:

  

所有文字字符串和字符串值常量表达式均已插入。字符串文字是在 Java™语言规范的第3.10.5节中定义的。

您已经通过将字符串引用与为"11"调用后出现的文字intern()创建的引用进行比较来利用此行为。但是,当您的代码以String s1 = new String("11")+new String("");开头时,您在调用之前 有一个字符串文字"11",该字符串将自动添加到池中。表达式new String("11")+new String("")创建一个新的String实例,该实例与字符串文字不同,并且没有添加到池中,因为已经有一个内容相同的字符串。

当我们实际使用返回值时,这很容易证明:

String s1 = new String("11")+new String("");
String shouldBeInPool = s1.intern();

String s2 = "11";

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

打印true

请注意,您的第一个示例

String s1 = new String("1")+new String("1");

s1.intern();

String s2 = "11";
System.out.println(s1 == s2);

将在较旧的JDK上打印false,例如Sun的JDK 6。

答案 1 :(得分:0)

无论何时创建字符串对象,都会创建两个对象,即一个在堆区域中,一个在字符串常量池中,并且字符串对象引用始终指向堆区域对象。因此将在堆区域中创建一个新的String(“ 11”)对象,并且s1引用指向堆。您可以访问的详细信息:https://www.geeksforgeeks.org/interning-of-string/,希望您喜欢!