public static void main(String[] args) {
String a = new StringBuilder("Jav").toString();
a.intern();
String c = "Jav";
System.out.println(a == c); //false
}
public static void main(String[] args) {
String a = new StringBuilder("Ja").append("v").toString();
a.intern();
String c = "Jav";
System.out.println(a == c); //true
}
我不明白为什么第一个打印出来的是假的,而第二个打印出来的是真的。我认为这些应该打印出true,因为在调用intern方法之后,a的引用将被写入字符串池,c将指向a的引用。有人能解释一下区别吗?谢谢你,谢谢
我的JDK版本:OpenJDK 17.0.7
顺便说一句,我也得到了同样的结果时,使用StringBuffer。
3条答案
按热度按时间qzwqbdag1#
TL;DR及解决方案
重要的区别是第一个
"Jav"
文字/interning的位置。intern()
* 返回 * 规范引用。如果规范引用已经存在,则不会更新它。因此,您需要将
a.intern();
更改为a = a.intern();
:为什么以及如何示例不同
在第二个示例中,
==
返回true
,因为StringBuilder
返回的String
在第一个intern()
调用中成为规范引用,而String
字面量被惰性解析并给出。然后,字面量给你一个规范引用,它是你已经拥有的同一个对象。
在第一个例子中,规范
String
已经存在,因此intern()
方法只返回 * 现有 * 规范String
,而不是使当前String
规范。进一步评论
有关代码的更详细分析,请参阅@Nidheesh R的answer。
正如@Jorn的评论中提到的,无论如何你不应该需要
String#intern
,你也不应该在String
上使用==
。此外,依赖这种行为是脆弱的。如果你使用的是像GraalVM的
native-image
这样的工具,使用不同的JVM或者Project Leyden的冷凝器,这样的东西可能会有点不同。des4xlb02#
正如@dan1st所提到的,这是由于
intern()
方法在Java中的工作方式。第一个
main
方法1.您正在使用
StringBuilder
创建一个新的String
对象a
,然后对其调用toString()
。这将创建一个值为“Jav”的新String
对象。1.然后,调用
a.intern()
,它尝试将字符串“Jav”添加到字符串池中。但是字符串池中已经有一个字符串“Jav”(因为new StringBuilder("jav");
)。因此,intern()
-调用什么也不做,a
仍然引用新创建的String
对象。1.最后,当您使用
a == c
比较a
和c
时,它会检查它们是否引用同一个对象。在这种情况下,它们不会这样做,因为a
引用新创建的String
对象,而c
引用字符串池中的“Jav”字符串。因此,结果是假的。第二个
main
方法1.您正在使用
StringBuilder
通过将“Ja”和“v”追加在一起来创建一个新的String对象a
。这将创建一个值为“Jav”的新String
对象。1.然后,调用
a.intern()
,它尝试将字符串“Jav”添加到字符串池中。但是,由于字符串“Jav”不在字符串池中,它会添加它,并返回字符串池中的字符串引用。1.现在,当您使用
a == c
比较a
和c
时,它们引用的是字符串池(由a.intern()
创建的字符串池)中的同一个字符串对象,返回的结果为true。mrphzbgm3#
比较字符串时使用String.equals()方法通常是一个好的做法,而不是==。
当我在第一个示例中使用
System.out.println(a.equals(c));
时,结果为true。请参阅此处的API规范。