Java对象分配

我是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上的所有对象?

你是对的,但是Strings是一个特例; 它们是不可变的,在这种情况下就像原始一样。

@newacct

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

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

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

@ user1238193

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

t1和t2将指向同一个对象。 对于任何java对象都是如此(包括不可变对象)

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

 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”的对象。

你是绝对正确的,因为t1和t2都指向同一个对象,对象状态中的任何chane都会影响到两者。

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

在这两种情况下,你做的事情完全不同。 在第一种情况下, 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就是这种情况。 但是如果你根本不做任何改变它的话,一个可变类会以完全相同的方式工作。

字符串对象是不可变的 。


编辑

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

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

但是,当你使用String s执行此操作然后执行类似s1 = "1" ; 你正在使s1指向另一个String对象。 你可以用s1 = new String(1);来思考它s1 = new String(1);

String就像任何其他对象一样。 因此,您指定的任何变量都指向对象的同一实例,就像您使用测试对象一样。

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

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

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

t2仍然有价值12