为什么不可变的新String(“fish”)!= new String(“fish”)?

时间:2011-10-20 21:39:19

标签: java immutability puzzle effective-java

我记得在Bloch的 Effective Java 中阅读了一节,其中说大多数情况下,

String a = "fish";
String b = "fish";

在大多数情况下a == b因为字符串是不可变的。但是由于临时构造对象或其他类似的东西,新的String(“fish”)会产生一个独特的对象引用。

我浏览了Bloch关于equals(),不变性和对象创建的章节,但是我记得找不到这一点!撕掉我的头发,有没有人记得这是什么原因的描述?它甚至可能不在 EJ 中,但我想找到它。提示:这解释的是我的实际问题。

3 个答案:

答案 0 :(得分:10)

这与不变性无关。这是JVM处理字符串的方式。具有相同内容的字符串文字表示相同的对象(“字符串文字”大致意味着“用引号括起来的文本”)。 JVM中有一个字符串对象表,每个字符串文字在该表中只有一个对象。

但是,当您明确地创建新实例时,您将根据从表中获取的字符串对象构造一个新的字符串对象。

从不使用文字形成的任何字符串(但通过调用toString(),通过实例化等),您可以通过调用str.intern()从jvm表中获取对象。 intern()方法只返回存在的每个字符序列的一个实例。 new String("fish").intern()将返回与String s = "fish"

相同的实例

要记住两件事:

  • 从不使用new String("something")
  • 始终将字符串与equals(..)进行比较(除非您确实知道自己在做什么,并将其记录下来)

答案 1 :(得分:0)

我认为您正在寻找维护常量字符串池的String.intern()方法。

运算符'=='比较对象引用(地址),而.equals()是一个查看语义等价的方法调用。

编译器将查看String a =“fish”和String b =“fish”,然后可能会或可能不会指向同一地址。但是,如果你做a.intern(); b.intern()然后它可能会将它们放在同一个字符串池中并且== b。

答案 2 :(得分:0)

如果您正在寻找明确的描述,请转到定义:JLS § 3.10.5 String Literals

您应该熟悉的示例代码是,

  

因此,测试程序由编译单元(第7.3节)组成:

package testPackage;
class Test {
        public static void main(String[] args) {
                String hello = "Hello", lo = "lo";
                System.out.print((hello == "Hello") + " ");
                System.out.print((Other.hello == hello) + " ");
                System.out.print((other.Other.hello == hello) + " ");
                System.out.print((hello == ("Hel"+"lo")) + " ");
                System.out.print((hello == ("Hel"+lo)) + " ");
                System.out.println(hello == ("Hel"+lo).intern());
        }
}
class Other { static String hello = "Hello"; }
     

和编译单元:

package other;
public class Other { static String hello = "Hello"; }
     

产生输出:

true true true true false true