基础Java问题:字符串相等性

5
public class A {

    static String s1 = "I am A";

    public static void main(String[] args) {
        String s2 = "I am A";
        System.out.println(s1 == s2);
    }
}

上面的程序输出“true”。它们是两个不同的标识符/对象,为什么输出是“true”?
我的理解是JVM会为每个对象创建不同的引用,如果是这样,那么输出怎么会是true呢?
5个回答

19

Java管理着一个字符串字面量池。在可以重用这些字面量时,它会进行重用。因此,这两个对象实际上是同一个字符串对象,== 返回 true。

我相信这被称为字符串驻留


1
关于字符串池的相关信息,请查看维基百科:http://en.wikipedia.org/wiki/String_interning(+1 同样的想法) - Felix Kling
1
是的,字符串字面量会自动进行内部化,就像 intern 方法 API 所述 - http://java.sun.com/javase/6/docs/api/java/lang/String.html - Ash
1
不仅字面量被内部化,编译时常量也是如此。 - Michael Borgwardt
4
请注意,不要依赖这个事实。当你想表达相等性时,请使用 equals :-)。当人们轻描淡写地发布关于字符串驻留的内容时,我总是感到紧张... 显然答案是正确的,我不怀疑这一点,但我想强调一下,虽然它解释了答案,但它不应该成为我们所依赖的东西(正如Josh Bloch指出的那样,它是一个实现细节,而不是程序员的工具)。 - Tom
2
语言规范中强制执行的某些内容并不是实现的细节,但我同意:虽然您可以依赖字面量被内部化,但不应该依赖您使用的字符串是字面量——因为这太容易改变了。 - Michael Borgwardt

5

== 检查变量是否指向同一个对象实例。你创建的两个字符串文字指向内存中的同一位置,因此它们是相等的。字符串文字被汇编在一起,因此相同的字符串文字在内存中是相同的对象。

如果您执行以下操作

String s = new String("foo");
String t = new String("foo");

那么 == 将返回 false,而 s.equals(t) 将返回 true。


5
这是由编译器执行的内存优化,即 String 常量(即由相同的 String 文字创建的 String)使用相同的 String 对象,因为 Strings 是不可变的。 == 运算符只检查两个对象是否为同一个实际对象。
如果您可以阅读 Joshua Bloch 和 Neal Gafter 的书 Java Puzzlers 并查看第13个谜题“Animal Farm”...他在这个问题上给出了很好的建议。我将复制一些相关文本:
“您可能已经知道类型为 String 的编译时常量被联接[JLS 15.28]。换句话说,任何两个类型为 String 的常量表达式,它们指定相同的字符序列,则通过相同的对象引用来表示... 除非需要比较对象标识而不是值,否则比较对象引用时,应优先使用 equals 方法而不是 == 运算符。”
这是我提到的参考资料... 在我的书中的第30-31页。

1
我提到了这个(尽管我没有提到它为什么这样做),结果被投票否决了。 - monksy

4

因为Java语言规范中提到:

字符串字面量,或者更一般地说,作为常量表达式(§15.28)的值的字符串,会被“interned”以共享唯一实例,使用String.intern方法。


1

你没有比较字符串的内容,而是只比较对象的引用。你应该使用equal方法(它是String类的成员)。或者你可以使用compareTo方法(也在同一个String类下)来检查返回值是否为零。

请注意上面的文本更多地是对原始问题状态的强烈建议,因为似乎OP不知道幕后实际发生的过程。

其他人建议使用intern()是正确的。为了回答这个问题,我没有足够的时间去看Java Puzzlers书。我确实怀疑在编译时设置相同的引用,但我也不知道如何找到对它的引用。


1
@Felix。不是的,他正在比较引用,输出结果为true - 这正是引发这个问题的稍微令人惊讶的结果。 - Michael Borgwardt
2
当我第一次阅读这个问题时,一个完全错误的答案实际上有一些赞成票,而当这个人附近的话题变得模糊不清时,他却遭到严重的反对,这对我来说感觉很奇怪。 - Steve De Caux
1
@Steve De Caux:我知道 :-)。像这样的回答,我倾向于不予理睬。这些答案的作者往往会误读问题或没有意识到问题的重要部分。我往往把我的踩放在那些完全错误或离题的帖子上。(例如,Pavel的回答)。 - Tom
2
我感到沮丧的是,现在人们来到这个页面时(大多数情况下),他们只会给被接受的答案点赞。当一个问题已经有了很多赞或者已经被接受后,提交一个经过深思熟虑或者写得很好的答案就变得非常困难。 - Tom
1
我的观点是,在第一次问问题时,他没有提到他理解了引用的处理方式,所以我插话并提到这是关于引用的...然后我出去查看为什么可能存在这种特殊情况。 - monksy
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接