[英]Confusion in String concatenation operator “+” in Java
据我所知,我们不能使用==
运算符来比较Java中的String
值。 所以我写了下面的代码:
public class Test {
public static void main(String[] args) {
String s1 = "My Computer";
String s2 = "My" + " Computer";
System.out.println(s1 == s2);
}
}
而且我期望结果是false
因为这是两个不同的对象,它们分配了不同的内存位置(如果我错了,请对此进行纠正)。 但是当我执行代码时,输出为true
。
然后我将s2
的值更改为:
String str = "My";
String s2 = str + " Computer"; //instead of "My" + " Computer"
然后,当我执行代码时,输出为false
。
现在,尽管我在两个语句中都使用了+
(不是concat()
方法),但我无法理解这两个语句的区别。 任何人都可以解释。
Java为String对象使用一个池-它试图变得聪明。 这意味着当编译器可以确定您实际上具有相同的对象时,即使两个看似不同的对象上的==
返回true。
但是,如果要比较内容,则应避免通过==
比较对象,因为这只会比较对象引用。 对于内容比较,应使用equals
。
您的测试用例中有一个愚蠢的错误。 String s2 = s1 + " Computer";
将为s2
分配字符串“ My Computer Computer ”,而不是“ My Computer”。
有关如何进行Java字符串比较的信息,请访问此链接。
为什么在Java中String是不可变的 -一篇文章解释了为什么不能在Java中修改String类的实例。 请阅读以清楚起见。
令您大跌眼镜的是此部分规范 :
除非表达式是常数表达式(第15.28节),否则将重新创建String对象(第12.5节)。
因此,当您将一个字符串常量连接到另一个字符串常量时,该常量将视为一个常量表达式,因此将在编译时求值并替换为字符串常量“我的电脑”。
您可以通过在已编译的类上运行javap -c
来验证这一点。
public class Test {
public static void main(String[] args) {
String s1 = "My Computer";
String s2 = "My" + " Computer";
String s3 = "My";
String s4 = s3 + " Computer";
System.out.println(s1 == s2); //true
System.out.println(s1 == s4); //false
}
}
编译为:
public static void main(java.lang.String[]);
Code:
// s1 = "My Computer"
0: ldc #2 // String My Computer
2: astore_1
// s2 = "My" + " Computer"
3: ldc #2 // String My Computer
5: astore_2
// s3 = "My"
6: ldc #3 // String My
8: astore_3
// s4 = s3 + " Computer"
9: new #4 // class java/lang/StringBuilder
12: dup
13: invokespecial #5 // Method java/lang/StringBuilder."<
init>":()V
16: aload_3
17: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: ldc #7 // String Computer
22: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: invokevirtual #8 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
28: astore 4
... the rest of the code omitted
如您所见,前两个赋值(到s1
和s2
)加载完全相同的常量( #2
),因此使用相同的对象。 而分配给s4
没有被定义为一个常量表达式 (即使有足够聪明的编译器可以计算出来,它是不允许),因此你会得到整个“创建一个StringBuilder,字符串追加到它,转换结果转换为新字符串”过程。
除了有趣的是,如果在上面的代码中将final
修饰符添加到s3
,这将使s3 + " Computer"
再次成为常量表达式,并且两个比较都将输出true
。
毫无疑问,您已经知道,代码的正确性不必依赖于所有这些,但这是一件很有趣的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.