试图完全掌握Java的传值。我们假设我们有这段代码:
public class Test {
static void switchIt(Test t) {
t = new Test();
}
public static void main(String ... args) {
Test a = new Test();
switchIt(a);
}
}
当a
引用的对象传递给switchIt()
时,引用值将复制到t
。因此,我们有两个 不同的 引用变量,其相同的位模式指向堆上的单个对象。
当t = new Test()
运行时,显然a
仍然引用旧对象,而t
现在指向堆上的新对象。由于a
和t
引用变量曾经具有相同的位模式,这是否意味着Java隐式更改了t
引用变量的位模式?或者假设位模式始终与之相同是错误的吗?
让我们说a
引用变量在堆栈上表示为0001.当我将它传递给函数时,这意味着t
在堆栈上也表示为0001,因为我传递了参考变量中的位副本。
当我将t
分配给new Test()
时,如果t
和a
两者在堆叠中都表示为0001,则{0001}会更改t
?
答案 0 :(得分:2)
是的,t
的引用将更改为指向新分配的Test
实例。你的理解是正确的。
当switchIt()
方法返回时,不再有对该新对象的任何引用。它现在有资格进行垃圾收集,而a
继续引用的原始对象在main()
返回之前将无法收集。
答案 1 :(得分:1)
这样想:
Java没有传递对象,它正在传递对象的内存指针。创建新对象时,它会获得一个新指针。所以当我们说java总是按值传递时,它是因为它总是传递对象的指针,这是一个数值。
即使对象彼此相等(a.equals(t))也可能返回true - 它们不相同,因为它们具有不同的指针,因此是驻留在不同存储空间中的不同对象。
使用您的编辑示例。 a会有0001但是t会是0002
Is Java "pass-by-reference" or "pass-by-value"?
希望有所帮助
答案 2 :(得分:1)
我认为你明白了,但你没有说得太好。这是一个更深入的解释,虽然实现可能不是我所描述的100%。
编译该代码时,将为每个方法创建一个称为“堆栈帧”的结构。每个堆栈帧将在其中保留足够的空间用于参数,局部变量等。基本上它会有足够的资源让你的方法做它的事情。所有这些堆栈帧都放在“堆栈”中:)
运行代码时,在main
中创建Test
的新实例并将引用分配给变量a
,或者更确切地说,分配给保留的堆栈帧中的位置变量a
。实际的对象将存储在堆上,而变量a
只会保存该对象的内存地址,正如您已经知道的那样。
当您调用switchIt
时,运行时会将引用a
的副本发送到方法switchIt
的堆栈帧。此堆栈帧具有足够的空间用于参数,并将其存储在其保留空间中。但是你在switchIt
中所做的是用刚刚创建并放在堆上的新对象替换存储在该保留空间中的初始值。现在堆上有两个对象,每个堆栈框架都包含其中一个引用。
答案 3 :(得分:1)
我认为代码会更清楚你。检查每个print语句中的哈希码,它不是内存位置,但它可以帮助你理解你的问题的答案。
class Ideone
{
static void switchIt(Ideone t) {
System.out.println("Object t "+t); // print statement 2
t = new Ideone();
System.out.println("object t after changing t "+t); // print statement 3
}
public static void main(String[] args) {
Ideone a = new Ideone();
System.out.println("object a "+a); // print statement 1
switchIt(a);
System.out.println("object a after calling switchIt() "+a); // print statement 4
}
}
object a Ideone@106d69c
Object t Ideone@106d69c
object t after changing t Ideone@52e922
object a after calling switchIt() Ideone@106d69c
print语句1,2,4具有相同的哈希码,但是3具有不同的哈希码。
<强> 1。创建对象a
<强> 2。将a
传递给switchIt(Ideone t)
:
第3。将t
更改为new Ideone()
:
注意:哈希码不是实际的内存位置。