Java - 按值传递 - 垃圾收集
Java - Pass By Value - Garbage Collection
试图完全掌握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
?
这样想:
Java 不是传递对象,而是传递对象的内存指针。当您创建一个新对象时,它会获得一个新指针。所以当我们说 java 总是按值传递时,这是因为它总是传递数值对象的指针。
即使对象彼此相等 (a.equals(t)) 也可能 return 正确 - 它们并不相同,因为它们具有不同的指针,因此是驻留在不同内存中的不同对象space。
使用您的编辑示例。 a 会有 0001 但 t 会是 0002
Is Java "pass-by-reference" or "pass-by-value"?
希望对您有所帮助
是的,t
的引用将更改为指向新分配的 Test
实例。在这一点上你的理解是正确的。
当 switchIt()
方法 returns 时,不再有对该新对象的任何引用。它现在符合垃圾回收条件,而 a
继续引用的原始对象将无法回收,直到 main()
returns.
我想你明白了,但你没有表达得很好。这里有一个更深入的解释,尽管实现可能不是我描述的 100% 完全一样。
编译该代码时,将为每个方法创建一个名为 "stack frame" 的结构。每个堆栈帧将在其中包含足够的 space 用于参数、局部变量等。基本上它将有足够的资源供您的方法执行其操作。所有这些堆栈帧都放在 "the stack" :)
当您 运行 您的代码时,在 main
中创建了 Test
的新实例并将引用分配给变量 a
,或者更准确地说,分配给堆栈帧中为变量 a
保留的位置。实际对象将存储在堆上,您的变量 a
将仅保存该对象的内存地址,正如您已经知道的那样。
当您调用switchIt
时,运行时间会将引用a
的副本发送到方法switchIt
的堆栈帧。此堆栈框架有足够的 space 用于您的参数,它将把它存储在其保留的 space 中。但是您在 switchIt
中所做的是用来自刚刚创建并放置在堆上的新对象的新引用替换存储在保留 space 中的初始值。现在堆上有两个对象,每个堆栈帧都包含这些引用之一。
我认为代码会让你更清楚。检查每个打印语句中的哈希码,它不是内存位置,但它会帮助你理解问题的答案。
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
打印语句 1、2、4 具有相同的哈希码,但 3 具有不同的哈希码。
1.创建对象 a
2。将 a
传递给 switchIt(Ideone t)
:
3。将 t
更改为 new Ideone()
:
注意:哈希码不是实际内存位置。
试图完全掌握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
?
这样想:
Java 不是传递对象,而是传递对象的内存指针。当您创建一个新对象时,它会获得一个新指针。所以当我们说 java 总是按值传递时,这是因为它总是传递数值对象的指针。
即使对象彼此相等 (a.equals(t)) 也可能 return 正确 - 它们并不相同,因为它们具有不同的指针,因此是驻留在不同内存中的不同对象space。
使用您的编辑示例。 a 会有 0001 但 t 会是 0002
Is Java "pass-by-reference" or "pass-by-value"?
希望对您有所帮助
是的,t
的引用将更改为指向新分配的 Test
实例。在这一点上你的理解是正确的。
当 switchIt()
方法 returns 时,不再有对该新对象的任何引用。它现在符合垃圾回收条件,而 a
继续引用的原始对象将无法回收,直到 main()
returns.
我想你明白了,但你没有表达得很好。这里有一个更深入的解释,尽管实现可能不是我描述的 100% 完全一样。
编译该代码时,将为每个方法创建一个名为 "stack frame" 的结构。每个堆栈帧将在其中包含足够的 space 用于参数、局部变量等。基本上它将有足够的资源供您的方法执行其操作。所有这些堆栈帧都放在 "the stack" :)
当您 运行 您的代码时,在 main
中创建了 Test
的新实例并将引用分配给变量 a
,或者更准确地说,分配给堆栈帧中为变量 a
保留的位置。实际对象将存储在堆上,您的变量 a
将仅保存该对象的内存地址,正如您已经知道的那样。
当您调用switchIt
时,运行时间会将引用a
的副本发送到方法switchIt
的堆栈帧。此堆栈框架有足够的 space 用于您的参数,它将把它存储在其保留的 space 中。但是您在 switchIt
中所做的是用来自刚刚创建并放置在堆上的新对象的新引用替换存储在保留 space 中的初始值。现在堆上有两个对象,每个堆栈帧都包含这些引用之一。
我认为代码会让你更清楚。检查每个打印语句中的哈希码,它不是内存位置,但它会帮助你理解问题的答案。
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
打印语句 1、2、4 具有相同的哈希码,但 3 具有不同的哈希码。
1.创建对象 a
2。将 a
传递给 switchIt(Ideone t)
:
3。将 t
更改为 new Ideone()
:
注意:哈希码不是实际内存位置。