Java中String intern方法在StringBuilder拼接场景下的表现差异疑问
为什么两段String.intern()代码执行结果不同?
我在OpenJDK 17.0.7环境下运行以下两段Java代码,执行结果的差异让我困惑——原以为调用intern()后两段代码都会输出true,实际却不一样;用StringBuffer替换StringBuilder也得到相同结果。
代码示例
代码1(输出false)
public static void main(String[] args) { String a = new StringBuilder("Jav").toString(); a.intern(); String c = "Jav"; System.out.println(a == c); //false }
代码2(输出true)
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 }
差异原因
核心区别在于字符串常量池中是否提前存在"Jav"这个字符串实例:
代码1的逻辑:
new StringBuilder("Jav").toString():这里的"Jav"是字符串字面量,在编译阶段就会被存入字符串常量池;而toString()方法会在堆内存中创建一个全新的String对象,赋值给变量a。- 调用
a.intern()时,JVM发现常量池中已经存在"Jav"的实例,因此不会将a的引用存入常量池,直接返回常量池中原有的实例。 String c = "Jav":直接指向常量池里原本就存在的"Jav"实例,和堆中的a不是同一个对象,所以a == c比较结果为false。
代码2的逻辑:
new StringBuilder("Ja").append("v").toString():"Ja"和"v"作为字面量会在编译阶段进入常量池,但拼接后的"Jav"是运行时动态生成的,编译阶段不存在这个字面量,因此常量池中一开始没有"Jav"的实例。- 调用
a.intern()时,JVM在常量池中找不到"Jav",就会将堆中a的引用存入常量池。 String c = "Jav":会直接指向常量池中存储的a的引用,此时a和c指向同一个堆对象,所以a == c比较结果为true。
内容的提问来源于stack exchange,提问作者Mattyeh
相关产品推荐
相关产品推荐

