使用StringBuilder和append方法创建String时Java String intern方法的问题

gcmastyq  于 2023-10-14  发布在  Java
关注(0)|答案(3)|浏览(100)
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。

qzwqbdag

qzwqbdag1#

TL;DR及解决方案

重要的区别是第一个"Jav"文字/interning的位置。
intern() * 返回 * 规范引用。如果规范引用已经存在,则不会更新它。
因此,您需要将a.intern();更改为a = a.intern();

public static void main(String[] args) {
    String a = new StringBuilder("Jav").toString();
    a = a.intern();
    String c = "Jav";
    System.out.println(a == c); //this is true now
}

为什么以及如何示例不同

在第二个示例中,==返回true,因为StringBuilder返回的String在第一个intern()调用中成为规范引用,而String字面量被惰性解析并给出。
然后,字面量给你一个规范引用,它是你已经拥有的同一个对象。
在第一个例子中,规范String已经存在,因此intern()方法只返回 * 现有 * 规范String,而不是使当前String规范。

进一步评论

有关代码的更详细分析,请参阅@Nidheesh Ranswer
正如@Jorn的评论中提到的,无论如何你不应该需要String#intern,你也不应该在String上使用==
此外,依赖这种行为是脆弱的。如果你使用的是像GraalVM的native-image这样的工具,使用不同的JVM或者Project Leyden的冷凝器,这样的东西可能会有点不同。

des4xlb0

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比较ac时,它会检查它们是否引用同一个对象。在这种情况下,它们不会这样做,因为a引用新创建的String对象,而c引用字符串池中的“Jav”字符串。因此,结果是假的。

第二个main方法

1.您正在使用StringBuilder通过将“Ja”和“v”追加在一起来创建一个新的String对象a。这将创建一个值为“Jav”的新String对象。
1.然后,调用a.intern(),它尝试将字符串“Jav”添加到字符串池中。但是,由于字符串“Jav”不在字符串池中,它会添加它,并返回字符串池中的字符串引用。
1.现在,当您使用a == c比较ac时,它们引用的是字符串池(由a.intern()创建的字符串池)中的同一个字符串对象,返回的结果为true。

mrphzbgm

mrphzbgm3#

比较字符串时使用String.equals()方法通常是一个好的做法,而不是==。
当我在第一个示例中使用System.out.println(a.equals(c));时,结果为true。
请参阅此处的API规范。

相关问题