Java字符串字面量拼接机制、对象创建位置及池化问题解析
Java字符串拼接与常量池问题解析
一、字符串拼接的两种场景与对象创建规则
Java里字符串拼接分两种情况,对象创建的位置和逻辑完全不同:
- 编译期可确定的字面量拼接:比如直接写
"ja" + "va",编译器会自动优化成完整的"java",这个字符串对象会被创建在字符串常量池中(属于方法区的一部分),而且常量池里不会存在重复的字面量,只会保留一份。 - 运行时动态拼接(变量参与的拼接):如果拼接的是变量(比如代码里的
b + c),编译期没法确定最终结果,运行时会通过StringBuilder的append方法拼接,最后调用toString()生成新的String对象——这个对象是创建在堆内存里的,不会自动进入字符串常量池。
二、代码运行结果分析
先看给出的代码:
class StringClass { public static void main(String[] args) { String a = "java"; String b = "ja"; String c = "va"; String d = b + c; System.out.println(a == d); } }
逐行拆解逻辑:
String a = "java";:直接从字符串常量池获取(或创建)"java"对象,a指向常量池中的这个对象引用。String b = "ja";和String c = "va";:同理,b、c分别指向常量池中的"ja"、"va"对象。String d = b + c;:因为b和c是变量,编译期无法确定拼接结果,运行时会执行以下逻辑:- 新建
StringBuilder对象 - 调用
append(b)和append(c)完成拼接 - 调用
toString()生成新的String对象,这个对象存放在堆内存中,d指向堆上的这个引用。
- 新建
System.out.println(a == d);:==在Java中比较的是对象的引用地址,a指向常量池的"java",d指向堆上的"java",两者地址不同,所以返回false。
三、关于常量池的疑问解答
你提到的“若变量a和d都属于字符串常量池”是错误的——d指向的对象不在字符串常量池里,只有编译期确定的字面量或手动调用intern()方法的字符串才会进入常量池。如果想让d指向常量池的对象,可以修改代码为String d = (b + c).intern();,此时a == d会返回true。
内容的提问来源于stack exchange,提问作者Aniket_Mishra
相关产品推荐
相关产品推荐

