对象 a = 对象 b; 对象 a 会发生什么?

11

我的一位教授给了我们几个练习题,其中一个问题的伪代码如下:

a.setColor(blue);
b.setColor(red);
a = b;
b.setColor(purple);
b = a;
//what color is a, and what color is b?

对我来说,这似乎非常基础,所以我建议答案是a为“红色”,b为“红色”,但被告知这是不正确的。我像解数学问题一样分解了我的答案:

a = 15;
b = 12;
a = b; //a becomes 12
b = 13;
b = a; //b becomes 12

但我的思考过程是通过C语言的思维方式,而不是Java。我认为有一些通用的方法适用于两种语言,但也许我错了?我的答案错了还是我的教授错了?虽然我对C、Python和Web逻辑(PHP、Ruby)有一些掌握,但我非常新手Java,所以如果这是一些微不足道的东西(它确实是),请原谅我。


在第一个例子中,ab是具有setColor方法的对象。而在第二个例子中,它们是简单的整数原始类型。这两个例子并不相同,因为你正在处理不同的事物。 - Marc B
@MarcB,我知道这一点,但是我认为无论使用数学还是颜色,变量初始化都应该保持一致。 - gator
2
分配对象和分配原始类型具有不同的语义。 - Marc B
1
为什么不在Java中设置示例并尝试它呢? - Brad Allred
2
颜色是紫色的,因为它们指向内存中的同一对象,所以当你改变b时,你同时也在改变a(修改由ab引用的对象)。 - Cold
显示剩余3条评论
6个回答

19
假设您已经创建了两个对象,并且将变量 ab 引用到它们,那么最初您会得到类似这样的东西。

假设您已经创建了两个对象,并且将变量 ab 引用到它们,那么最初您会得到类似这样的东西。

a -->  [ white ]     b --> [ white ]

您的前两行更改了对象的颜色,以给您

a -->  [ blue  ]     b --> [  red  ]

接着,您将变量a指向由b引用的对象,使它们都指向同一个对象。现在您拥有了

       [ blue  ]     b --> [  red  ] <-- a

然后你改变了由b引用的对象的颜色。

       [ blue  ]     b --> [ purple ] <-- a

最后,代码行 b=a; 不起作用,因为 b 已经引用与 a 相同的对象。


6
在第一个示例中,ab都是对象,所以以下是每个步骤发生的情况:

a <-- 是一个对象

b <-- 是一个对象

a.setColor(blue); <-- a 变成了蓝色

b.setColor(red); <-- b 变成了红色

a = b; <-- 重要:: 原始的 a 对象被释放并且现在可以进行垃圾收集。现在 a 持有 b 对象的引用,这意味着 ab 现在都指向同一个对象,即 b

b.setColor(purple); <-- b 现在是紫色的。由于 a 只指向 b,a 也是紫色的

回答: 在此时,ab都是紫色的。


1
在执行a=b;后,a引用的对象会发生什么?现在没有办法引用它了吗? - gator
5
它将被垃圾回收。 - tomato
1
@riista:由于上面的代码片段中没有任何变量持有a的引用,因此a可以被垃圾回收。 - Yogendra Singh

4
重要的是要认识到,在执行了代码行 a = b 后,你将不再拥有两个对象,而是有两个变量,它们都指向同一个对象。因此,当你改变这个对象的颜色时,两个变量都会反映出来。而代码行 b = a 实际上并没有做任何事情。

3
在Java中,通常可以将任何作为对象的变量视为指向该对象类型值的指针。因此,在Java中,以下内容是正确的:
Color a = new Color(), b = new Color();

a.setColor(blue);
b.setColor(red);
a = b;
b.setColor(purple);
b = a;

应该和C++中的以下代码做更多或更少相同的事情:

Color *a = new Color();
Color *b = new Color();

a->setColor(blue); // the value a points to is now blue
b->setColor(red); // the value b points to is now red
a = b; // a now points to the same value as b.
b->setColor(purple); // the value BOTH a and b point to is now purple
b = a; // this does nothing since a == b is already true

(请注意,这与引用不同-如this article所述。)
另外请注意,对于原始类型,Java变量仅仅是值-不是指针。因此,在原始整数的情况下,它应该基本上按照您在问题中期望的方式运行,因为a = b正在将a的值设置为b的值。

2

ab是指向对象的引用(reference)。当你写a=b时,a被分配给之前分配给b的引用,因此它们现在都指向同一个对象。

所以,假设你有两个对象O1和O2,在开始时分别分配给ab

a.setColor(blue);     // the object O1 is set the color blue
b.setColor(red);      // the object O2 is set the color red
a = b;                // a now references O2, and b still references O2.
b.setColor(purple);   // the object O2 is set the color purple.
b = a;                // b is told to reference O2, which it already is.

如果你想通过C语言的思维方式来思考,你可以把ab看作指针,它们可以在变量之间交换,并且它们的数据可以被修改。对于原始值来说,情况并非如此,它们的处理方式类似于C语言。

2

既然其他人已经解释了引用和原始类型之间的区别,那么我将解释它在表面下的工作原理。

因此,对对象的引用本质上是一个数字。根据虚拟机(VM),它将是32位或64位,但它仍然是一个数字。这个数字告诉你对象在内存中的位置。这些数字称为地址,通常以十六进制基数书写,如0xYYYYYYYY(这是32位地址的示例,64位地址将是两倍大)。

让我们使用您上面的示例来使用32位VM。

a.setColor(blue); // Let's assume the object pointed to by a is at 0x00000001
b.setColor(red);  // Let's assume the object pointed to by b is at 0x00000010

/* Now the following makes sense, what happens is the value of 
   a (0x00000001) is overwritten with 0x00000010. 
   This is just like you would expect if a and b were ints.
*/
a = b; // Both a and b have the value 0x00000010. They point to the same object

b.setColor(purple); // This changed the object stored at 0x00000010 

b = a; // This says nothing because both a and b already contain the value 0x00000010

这应该说明引用像你在第二个例子中展示的数字一样工作。然而,只是在表面之下,就你程序员而言,与基元赋值不同,引用的赋值并不像工作。

在Java中,您永远不需要担心对象的地址和类似的问题。在像C和C++这样允许更低级别访问的语言中,这变得更加明显和重要。

算术?那么你能做数字可以做的算术和其他事情吗?简短的答案是不行,至少在Java中不行。

在C和C++中,增加和减少指向对象的指针是完全有效的,并且经常使用,例如遍历数组。

如果这不够清楚,请随时提问。


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