23

我是 Java 新手,我对对象分配有一些疑问。例如,

Test t1 = new Test();
Test t2 = t1;
t1.i=1;

假设变量i是在 Test 类中定义的,我是否正确假设 t1 和 t2 都指向同一个对象,其中修改t1.i=1会影响t1t2?实际上我测试了它,似乎我是对的。但是,当我在 上尝试相同的操作时String,修改仅发生在另一侧不受影响的一侧。这背后的原因是什么?

编辑:我尝试使用 String 的情况。

String s1 = "0";
String s2 = s1;          
s1 = "1";
System.out.println(s1);
System.out.println(s2);

我通过在 String 上测试案例来意识到我的错误,因为它是不可变的。我认为s1="1"修改字符串的情况实际上是将“1”的引用返回给s1。尽管如此,我的问题仍然存在。是否Test t2 = t1;导致 t2 和 t1 都指向同一个对象,或者现在每个都有自己的对象?这种情况是否适用于 Java 上的所有对象?

4

8 回答 8

19

你是对的,但字符串是一个特例;在这种情况下,它们是不可变的并且表现得像原语。

@newacct

我引用http://docs.oracle.com/javase/tutorial/java/data/strings.html

注意: String 类是不可变的,因此一旦创建 String 对象就无法更改。String 类有许多方法,其中一些将在下面讨论,它们似乎可以修改字符串。由于字符串是不可变的,这些方法真正做的是创建并返回一个包含操作结果的新字符串。

这就是使字符串成为特殊情况的原因。如果您不知道这一点,您可能希望引用中讨论的方法不会返回新字符串,这会导致意外结果。

@user1238193

考虑您的以下问题:“Test t2 = t1; 是否导致 t2 和 t1 都指向同一个对象,或者现在每个对象都有自己的对象?这种情况是否适用于 Java 上的所有对象?”

t1 和 t2 将指向同一个对象。这适用于任何 java 对象(包括不可变对象)

于 2012-06-13T09:17:47.287 回答
8

你的第一个假设是正确的。使用以下代码行:

Test t1 = new Test();

您创建一个新的 Test 对象,同时创建一个名为 t1 的 Test 引用来引用它。

在您发布的代码的第二行:

Test t2 = t1;

您实际上是在创建另一个 Test 引用,并将其分配给 t1 引用的同一对象。

所以t1.i = 1;会影响t2.i它毕竟是同一个对象。

至于字符串,字符串是不可变的,实例化后不能修改。

关于您的编辑:

String s1 = "0";
String s2 = s1;          
s1 = "1";
System.out.println(s1);
System.out.println(s2);

他们会打印出不同的结果,因为当你实际说

s1 = "1";

您实际上将 s1 绑定到另一个 String 对象,但 s2 仍将引用值为“0”的对象。

于 2012-06-13T09:22:01.177 回答
5

在这两种情况下,您正在做完全不同的事情。在第一种情况下,t1.i = 1;您正在修改 指向的对象t1。在第二种情况下,使用t1 = "1";,您将引用更改为指向另一个对象(类似于您使用t2 = t1;.

如果你Test对第二种情况做同样的事情,你会得到相同的结果(假设Test有一个接受整数的构造函数):

Test t1 = new Test(5);
Test t2 = t1;          
t2 = new Test(1); // Here we are assigning to the variable, just like your 2nd example
System.out.println(t1);
System.out.println(t2);

人们提到这String是不可变的。但这无关紧要,语言中没有“可变性”的概念,“可变”和“不可变”类的工作方式没有区别。如果一个类碰巧没有您可以设置的任何字段或任何可以更改其内部内容的方法,我们非正式地说它是“不可变的”。情况就是这样String。但是,如果您根本不做任何事情来改变它,那么可变类将以完全相同的方式工作。

于 2012-06-13T18:04:01.720 回答
3

你是绝对正确的,因为 t1 和 t2 都引用同一个对象,所以对象状态中的任何通道都会影响两者。

String 是一个不可变的对象。所以根本无法修改。有关 java 中不可变对象的更多信息,请参阅此内容。

于 2012-06-13T09:17:02.507 回答
2

字符串对象是不可变的


编辑

是否Test t2 = t1;导致 t2 和 t1 都指向同一个对象,或者现在每个都有自己的对象?

是的。虽然t2是一个新的引用,但它会指向同一个对象,因为你告诉它这样做。创建一个新t2的类型引用,Test让它指向同一个对象t1

但是,当您使用Strings 执行此操作然后执行类似s1 = "1" ;使 s1 指向另一个 String 对象的操作时。你可以用术语来想它s1 = new String(1);

于 2012-06-13T09:18:17.497 回答
1

字符串和其他对象一样是对象。因此,您分配给它们的任何变量都指的是对象的同一个实例,就像您对测试对象所做的那样。

但请记住,String 没有您可以像在 Test 上那样设置的字段,因此您基本上无法进行相同的测试,因此无法将您的代码从 Test 对象移植到 String 对象。

使用原始类型(如 long、int 等)会得到相反的行为。它们被“按值”分配给变量,所以如果你这样做

int t1 = 12;
int t2 = t1;
t1=15;

t2 仍然有值 12

于 2012-06-13T09:20:43.747 回答
0

因为java使用了字符串字面量的概念。假设有5个引用变量,都引用一个对象“0”。如果一个引用变量改变了对象的值,就会影响到所有的引用变量。这就是为什么字符串对象在 java 中是不可变的。

于 2020-10-20T06:33:19.563 回答
0

以 StringBuilder 为例会更清楚一点。以下示例显示了仅使用引用而不是值的对象分配。

{ StringBuilder str = new StringBuilder();

    str.append("GFG");

    StringBuilder str1 = str;

    str.append("tail");
    // output: str1 = GFGtail str = GFGtail
    System.out.println("str1 = " + str1.toString() + " str = " + str.toString());  

}

于 2020-05-07T02:46:59.187 回答