Java中的字符串为什么是引用类型?

12

我理解类是引用类型,例如我创建了以下类:

class Class {

String s = "Hello";

public void change() {
    s = "Bye";
} }

通过以下代码,我了解到Class是一个引用类型:

Class c1 = new Class(); 
Class c2 = c1; //now has the same reference as c1

System.out.println(c1.s); //prints Hello
System.out.println(c2.s); //prints Hello

c2.change(); //changes s to Bye

System.out.println(c1.s); //prints Bye
System.out.println(c2.s); //prints Bye

现在我想用一个字符串做同样的事情,但不起作用。这里我做错了什么?
String s1 = "Hello";
String s2 = s1; //now has the same reference as s1 right?

System.out.println(s1); //prints Hello
System.out.println(s2); //prints Hello

s2 = "Bye"; //now changes s2 (so s1 as well because of the same reference?) to Bye

System.out.println(s1); //prints Hello (why isn't it changed to Bye?)
System.out.println(s2); //prints Bye

5
你将引用变量和对象混淆了,需要了解它们之间的区别。 - Hovercraft Full Of Eels
2
字符串是不可变的,每当您“更改”一个字符串时,实际上只是创建了一个新的字符串,并更改了引用以指向新字符串。 - Chris Rollins
3
s2和s1不是同一个引用。它们最初是指向相同的字符串实例的两个不同引用……直到你执行s2 = "Bye"操作。 - JB Nizet
1
在Java中,“引用”与C/C++中不同。 s1s2是两个引用,都指向相同的字符串“Hello”。一旦更改s2,也就是让s2指向一个新的字符串“Bye”,而s1仍然指向原来的字符串“Hello”。 - zhh
2
此外,你不应该将你的类命名为 Class,因为 JDK 已经有一个(相当常用的)同名类。这会让人感到困惑;如果我看到一个叫做 Class 的类,我的默认假设是它是 JDK 中的那个。 - yshavit
显示剩余2条评论
5个回答

22

在第一个情况下,您调用了指向的对象的一个方法,因此更改的是指向的对象而不是2个引用:

method

在第二个情况下,您将新对象分配给引用本身,然后该引用指向该新对象:

new object


7
这是因为您更新了s2的引用而不是s1。让我们看看您的代码是如何执行的:
String s1 = "Hello";
String s2 = s1; 

String pool 中创建了一个 Hello 文本字符串,然后将其引用放入了 s1 中。然后在第二行,s2 也获得了相同的引用。

enter image description here

此时,s1s2 指向 String pool 中的同一个文本字符串。

现在执行下面的代码:

String pool 中创建另一个文本字符串 Bye 并将其引用放到 s2 中。然而,s1 仍然具有旧的引用,因此打印出来的是 Hello

![enter image description here


1
再次强调,字符串是不可变的这一事实并不重要。对于可变对象,行为也将完全相同。 - JB Nizet
@JBNizet 是的,同意...我更新了我的回答...我仍然不确定为什么我写了immutable...哈哈 - Aman Chhabra

0
s2 = "Bye"; 

这相当于创建一个新的字符串对象并将其引用分配给s2s2 = new String("Bye");),因此s1s2是不同的。

您正在将上述内容与像c2.change()这样的方法调用进行比较,该方法会更改一些内部字段值。

换句话说,s2 = "Bye";等同于您的示例中的Class c2 = new Class();。在执行c1.change()之后,您不能期望c1c2具有相同的字段s值。


1
@HovercraftFullOfEels 我同意不可变性不是问题。我会重新措辞。 - Thiyagu
不确定为什么还有dv,因为您的答案现在是正确的。 - Hovercraft Full Of Eels

-2

Java 是按值传递的。如果你将一个对象传递到方法中,那么实际上你只是传递了这个对象的值,而不是对象本身,它的值保持不变。


“the object itself” 是什么意思? - nicomp
我的意思是对象不是一个参数,只有对象的值。 - Paweł Jarosiewicz

-3

字符串 s1="Hello"; 字符串 s2=s1;

当你进行更改时,

s2="Bye";

你做的是

s2 = new String("Bye");

明确地


3
“拜拜”和使用new String("拜拜")创建的字符串不等价。 - JB Nizet
是的,我知道这个。只是为了解释这个概念。 - Hammad Tufail
那么为什么你的回答说执行s2="Bye";就相当于执行s2 = new String("Bye");呢?请解释这个概念,但不要说错话。 - JB Nizet
new 会为 s2 分配单独的内存,而不是将字符串加入字符串池中。 - Hammad Tufail
@JBNizet 我的错! - Hammad Tufail

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