我刚开始学习Java,但是我才刚刚开始了解值类型与引用类型。据我了解,字符串是引用类型。但是,与其他引用类型不同,我可以打印String而不用打印字母和数字的某种奇怪组合。这是为什么?而且,说我有代码
String s1 = "x";
String s2 = s1;
s1 = "xyz";
System.out.println(s2);
它将打印“ x”,而不是“ xyz”,即使我更改了s2所指的对象。当我更改一个数组时,这不会发生。为什么字符串很特殊?
答案 0 :(得分:5)
但是,与其他引用类型不同,我可以打印String而不用打印字母和数字的某些奇怪组合。为什么会这样?
因为与其他许多类型一样,字符串会覆盖Object.toString()
,并返回另一个字符串,而不是默认实现返回的字符串(当然,它会返回自身)。
当我更改一个数组时,不会发生这种情况。
您将“为变量分配新值”与“更改对象的状态”混为一谈。如果您执行的操作与使用数组执行的操作相同,则将具有相同的行为:
char[] s1 = new char[] {'x'};
char[] s2 = s1;
s1 = new char[] {'x', 'y', 'z'};
System.out.println(Arrays.toString(s2));
将不同的数组分配给s1
时,不会改变变量s2
指向的内容。
当然,如果s1和s2指向同一数组,而您修改了该数组,则它们都将始终指向同一修改后的数组:
char[] s1 = new char[] {'x'};
char[] s2 = s1;
s1[0] = 'y';
System.out.println(Arrays.toString(s2));
答案 1 :(得分:1)
看看Object#toString
的实现:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
现在,这是String#toString
的实现:
public String toString() {
return this;
}
调用System.out.println(String s)
直接打印内部char数组表示形式,而System.out.println(Object o)
的实现如下:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
最后,实现String#valueOf
:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
由于此,在未覆盖System.out.println
方法的对象上调用toString
导致调用Object#toString
,该方法返回由hashCode附加的类的名称。
关于第二个问题,请参见Java String variable setting - reference or value?