字符串相等性与位置相等性的区别

8
String s1 = "BloodParrot is the man";  
String s2 = "BloodParrot is the man";  
String s3 = new String("BloodParrot is the man");  

System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));

// 输出结果



如果三个字符串的内容相同,为什么它们在内存中的位置不都相同?


这是Java还是C#?对你的问题的回答似乎取决于语言。你可能希望相应地标记它。 - Doug T.
这不是重复的。这个问题更多地涉及字符串的实例化而不是比较它们。 - Bill the Lizard
我猜最后一条评论没有意义,除非我提到我撤销了一次编辑,说这个问题是另一个问题的重复。如果您不同意,请随时添加链接并投票关闭。 - Bill the Lizard
6个回答

15
Java只会自动地对字符串字面量进行常量池化,使用new关键字创建的新的字符串对象默认不会被常量池化。你可以通过使用String.intern()方法来将一个已有的字符串对象放入常量池中。调用intern会在现有的字符串常量池中查找匹配对象并返回,如果存在匹配对象则返回该对象,否则添加进常量池中。
如果你添加以下代码行:
s3 = s3.intern();

在创建了s3后,将下面的代码添加到您的代码中,您将看到输出结果的差异。

查看更多示例和更详细的说明

这当然涉及到Java中何时使用==和equals方法的非常重要的主题。在处理对象引用时,您几乎总是希望使用equals。==运算符比较引用值,这几乎永远不是您想要比较的内容。了解差异可以帮助您决定何时适当地使用==或equals


3
您明确调用了s3的new方法,这将为您留下一个新的字符串实例。

哦,所以唯一的区别就是使用了 "new" 关键字。那么没有使用 new 关键字的字符串不是字符串对象的实例吗? - BloodParrot
它们是实例,但不一定有专用缓冲区。 - sharptooth

2
创建一个 String 实际上是一个快速的过程。尝试查找任何先前创建的 String 将会慢得多。
考虑一下,要使所有的 String 都被内部化,你需要做什么。你需要搜索所有先前构造的 String 的集合。请注意,这必须以线程安全的方式完成,这增加了开销。因为你不想泄漏这个,所以你需要使用某种形式的(线程安全的)非强引用。
当然,你不能像这样实现 Java,因为库不幸地暴露了 String 和大多数其他不可变值对象的构造函数。

1

有一个叫做String.intern的方法,它基本上会将所有相同的字符串放入哈希表中(我有点撒谎,但对于这个概念来说重要的是概念本身,而不是现实)。

String s1 = "BloodParrot is the man";  
String s2 = "BloodParrot is the man";  
String s3 = new String("BloodParrot is the man").intern();  

System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));

应该让它们都是“true”。这是因为(我在这里有点撒谎,但这只涉及概念而非现实)String s1 =“BloodParrot is the man”; 做了类似于String s1 =“BloodParrot is the man”。intern();


1

1
为什么如果三个字符串的内容相同,它们不在内存中具有相同的位置?
因为它们是具有相同内容但不同的字符串!

字符串 s1 = "BloodParrot is the man"; 字符串 s2 = "BloodParrot is the man";s1 == s2 => true 看起来 s1 和 s2 是相同的字符串。 - Nicolas Dorier
这两个是相同的,指向同一地址。只有s3不同,因为它被明确地创建为一个新的字符串。 - erickson
1
s1和s2不一定是同一个对象。 - Steve Kuo

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