字符串作为引用类型

3

我对学习Java还比较新,但是我开始明白值类型和引用类型的区别。据我所知,String是引用类型。然而,与其他引用类型不同的是,我可以打印一个String而不会打印一些奇怪的字母和数字组合。这是为什么呢?此外,假设我有以下代码:

String s1 = "x";
String s2 = s1;
s1 = "xyz";
System.out.println(s2);

它将打印 "x",而不是 "xyz",即使我改变了对象 s2 引用的对象。当我改变数组时,这种情况不会发生。为什么字符串很特别?


3
字符串是不可变的。你没有改变s2引用的对象,你只是让s1引用了一个不同的字符串。 - Paul Rooney
Java中的字符串是不可变的,因此您的重新分配实际上会导致您的变量指向一个新的字符串实例,而不是更改字符串的值。 - Mohsen
2
这与不可变性没有真正的关系,这只是在Java中将不同的对象分配给变量的工作方式。 - Mark Rotteveel
@Calaf 那个问题所接受的答案和其他最高赞的答案价值存疑且不正确。我不确定将其建议为重复是否有帮助。 - Mark Rotteveel
2个回答

5
与其他引用类型不同,我可以打印字符串而不会打印一些奇怪的字母和数字组合。为什么呢?因为像许多其他类型一样,字符串重写了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

请看Object#toString的实现:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

现在,这是 String#toString 的实现:
public String toString() {
    return this;
}

调用 System.out.println(String s) 会直接打印内部字符数组表示,而 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();
}

由于这个原因,对于没有覆盖toString方法的对象调用System.out.println会导致调用Object#toString,其返回类名后附加hashCode。
关于您的第二个问题,请参见Java String变量设置 - 引用还是值?

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