Java中字符串字面量拼接后使用==比较结果为何不同?
为什么两种字符串拼接场景下
==比较结果不同? 这个问题的核心在于Java字符串编译期优化和运行期字符串拼接的区别,以及字符串常量池的工作机制,咱们一步步拆解:
1. 编译期常量拼接:直接复用常量池对象
先看返回true的代码:
public class Main { public static void main(String[] args) { String A = "hel" + "lo"; String B = "lo"; String C = "hel" + "lo"; System.out.println(A == C); // true } }
这里的"hel" + "lo"都是字符串字面量,Java编译器在编译阶段会自动将这种字面量拼接优化成完整的"hello",并且会把这个字符串存入字符串常量池(String Pool)。
当创建变量A和C时,它们都会直接指向常量池里同一个"hello"对象,所以用==比较引用地址时,结果自然是true。
2. 运行期变量拼接:生成新的堆对象
再看返回false的代码:
public class Main { public static void main(String[] args) { String A = "hel" + "lo"; String B = "lo"; String C = "hel" + B; System.out.println(A == C); // false } }
这里的"hel" + B中,B是一个字符串变量(哪怕它的值是字面量"lo"),编译器在编译阶段无法确定B的最终值(比如运行时B可能被修改),所以这种拼接会在运行阶段执行:
Java会创建一个StringBuilder对象,先append"hel",再append B的值,最后调用toString()生成一个新的String对象——这个对象是存在堆内存中的,而不是字符串常量池里。
而A指向的是常量池里的"hello",两者是不同的对象,所以==比较引用地址时返回false。
补充:如何让变量拼接也复用常量池对象?
如果把B用final修饰,变成编译期常量:
public class Main { public static void main(String[] args) { String A = "hel" + "lo"; final String B = "lo"; // 用final修饰,变成编译期常量 String C = "hel" + B; System.out.println(A == C); // true } }
此时编译器能确定B的值不会改变,会把"hel" + B优化成"hello",C也会指向常量池里的同一个对象,==就会返回true。
关键提醒
永远记住:==比较的是对象的引用地址,如果要比较字符串的内容,应该使用equals()方法,比如A.equals(C)在两种场景下都会返回true。
内容的提问来源于stack exchange,提问作者vishal joshi
相关产品推荐
相关产品推荐

