如果在不使用" new"声明它们的情况下对同一对象的字符串引用关键字如下:
String s1 = "Some string";
String s2 = "Some string";
System.out.println(s1 == s2);
//prints true because
//they reference to the same object
然而,与我的预期相反,数组不起作用:
char[] anArray = {'A', 'r', 'r', 'a', 'y'};
char[] oneArray = {'A', 'r', 'r', 'a', 'y'};
System.out.println("anArray == oneArray : " + (anArray == oneArray));
//prints false
我们没有明确提到他们是"新"数组,为什么它们不引用堆上的同一个对象?
答案 0 :(得分:8)
因为数组与字符串不同,所以是可变的。您通常不希望通过另一个变量引用的假定独立对象来更改从一个变量引用的对象。
char[] firstArray = {'A', 'r', 'r', 'a', 'y'};
char[] secondArray = {'A', 'r', 'r', 'a', 'y'};
firstArray[0] = 'X';
firstArray[1] = '-';
System.out.println(firstArray);
System.out.println(secondArray);
如果数组被“插入”(即如果相同的文字指向相同的实例),输出会是什么:
X-ray
X-ray
实际发生的事情:每个文字创建一个新实例:
X-ray
Array
答案 1 :(得分:4)
我们没有明确提到他们是"新"数组,为什么它们不引用堆上的同一个对象?
这里真正的问题是:为什么会他们?如果在一般情况下,等效对象被JVM混淆,那将是一个真正的痛苦。许多类都有可变实例;如果您有可变实例(并且数组是可变的)并且JVM将它们组合到单个实例中而没有您要求它,那么它就是位的问题。
通过扩展,真正的问题是:为什么s1
和s2
引用同一个对象?
答案是:因为字符串是JDK和JVM特殊处理的特殊情况。 Java中的字符串被设计为在可能的情况下共享,以节省内存大小和流失,所以:
他们是不可变的(虽然如果你足够努力就可以通过反思打破它),所以共享实例是可以接受的(因为你不会正式改变它们)。 / p>
字符串可以intern
ed,将它们放在JVM管理的字符串池中。
字符串文字会自动intern
ed。
s1
和s2
不会引用相同的字符串,如果它不是#3。示例(live copy):
String s1 = "Some string";
int a = 1;
String s2 = (a == 1 ? "Some" : "Foo") + " string";
System.out.println("Same? " + (s1 == s2));
System.out.println("Equivalent? " + s1.equals(s2));
输出:
Same? false Equivalent? true
由表达式生成并分配给s2
的字符串无法自动intern
,因此最终会引用 diffrent 字符串对象。< / p>
如果你有一个包含不可变实例的类,你也可以为它们实现intern
。字符串只是特殊之处,因为它是由Java规范和运行时为我们完成的。
答案 2 :(得分:3)
System.out.println(s1 == s2);
只返回true
因为我们有一个String常量池来检查这些文字(或实习字符串)并重用相同的字符串。数组从未为此设计过。
实际上:
String s1 = new String("Some string");
String s2 = new String("Some string");
将为false
提供System.out.println(s1 == s2);
。
答案 3 :(得分:1)
java中的字符串保存在字符串表中。当您创建两个完全相同的字符串时,它们将引用同一个对象。如果你想知道一个字符串的值是否与另一个字符串相同,你将不得不做String.Equals()。
由于数组未保存在数组表中,因此它们将引用不同的对象。你想知道两个数组的内容是否相同,你必须使用String.Equals()通过数组进行迭代。