为何这段Java代码的字符串比较结果因变量是否为final而异?
为什么String变量是否为final会影响==的比较结果?
咱们先拆解你给出的代码逻辑:
public class Example { public static void main(String[] args) { String a = "abc"; // Line 5 String b = a + "d"; // Line 6 String c = "abc"+ "d"; // Line 7 String d = "abcd"; //Line 8 System.out.println(b==c); //Line 10 输出false System.out.println(c==d); //Line 11 输出true } }
要搞懂这个差异,核心得理解Java的字符串常量池和编译期常量折叠两个关键机制:
1. 为什么c==d返回true?
"abc"+"d"里的两个操作数都是字符串字面量,属于编译期可确定的常量。编译器在编译阶段就会直接把这个拼接操作折叠成最终的"abcd",所以变量c指向的是字符串常量池里的"abcd"对象。而d直接赋值为"abcd",自然也指向常量池里的同一个对象。==比较的是对象的引用地址,所以结果为true。
2. 为什么b==c返回false?
当a没有被final修饰时,编译器无法保证a的值在运行时不会被修改(哪怕你代码里没改,编译器也不会做这个假设)。因此a + "d"这个操作只能在运行时执行:Java会通过StringBuilder的append方法拼接字符串,再调用toString()生成一个新的堆内存对象,这个对象并不在字符串常量池里。而c指向的是常量池里的"abcd",两个对象的引用地址不同,所以==比较返回false。
3. 把a改成final会发生什么?
如果给a加上final修饰:final String a = "abc";,此时a就变成了编译期常量——编译器可以确定它的值永远不会被改变。这时候a + "d"会被编译器直接折叠成"abcd",和"abc"+"d"的处理逻辑完全一致。变量b也会指向常量池里的同一个"abcd"对象,这时候b==c就会输出true了。
最后提醒一句:日常开发中,比较字符串内容是否相等一定要用equals()方法,==只比较对象引用,很容易因为常量池和运行时对象的差异出现不符合预期的结果。
内容的提问来源于stack exchange,提问作者Gaurav Priyadarshi
相关产品推荐
相关产品推荐

