据我所知,我们不能使用==
运算符来比较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()
方法)。任何人都可以解释一下。
答案 0 :(得分:2)
Java为String对象使用了一个池 - 它试图变得聪明。这意味着当编译器可以确定您实际拥有相同的对象时,即使两个看似不同的对象上的==
也会返回true。
然而,如果您想比较内容,应该避免通过==
比较对象,因为这只会比较对象引用。对于内容比较,应使用equals
。
答案 1 :(得分:2)
您的测试用例存在愚蠢的错误。
String s2 = s1 + " Computer";
将s2
字符串“我的电脑计算机”,而不是“我的电脑”。
如何进行字符串比较Java,请访问this链接。
Why String is immutable in Java - 一篇解释为什么无法修改Java中String类的实例的文章。请阅读此内容以获得清晰度。
答案 2 :(得分:2)
让你感到震惊的是this part of the specification:
除非表达式是a,否则新创建String对象(第12.5节) 常数表达式(§15.28)。
因此,当您将字符串常量连接到另一个字符串常量时,它将计为一个常量表达式,因此将在编译时进行计算,并替换为字符串常量“我的电脑”。
您可以通过在已编译的类上运行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
的赋值是而不是定义为constant expression(尽管一个足够聪明的编译器可以解决它,但是不允许),因此你得到了整个“创建一个StringBuilder,将字符串追加到它,将结果转换为新的字符串”进程。
有趣的是,如果在上面的代码中将final
修饰符添加到s3
,则会使s3 + " Computer"
再次成为常量表达式,并且两个比较都将打印{{1} }。
毫无疑问,您已经知道,您的代码的正确性不能依赖于所有这些,但知道它是一件有趣的事情。