【问题标题】:Java - Pass By Value - Garbage CollectionJava - 按值传递 - 垃圾收集
【发布时间】:2015-12-21 02:34:09
【问题描述】:

试图完全掌握 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 现在指向堆上的新对象。由于at 引用变量曾经具有相同的位模式,这是否意味着Java 隐式更改了t 引用变量的位模式?或者假设位模式从一开始就相同是错误的吗?


假设a 引用变量在堆栈上表示为 0001。当我将它传递给函数时,这意味着 t 在堆栈上也表示为 0001,因为我传递了位的副本参考变量。

当我将t 分配给new Test() 时,如果ta 在堆栈上都表示为0001,那么t 的0001 会改变吗?

【问题讨论】:

  • “由于 a 和 t 引用变量过去具有相同的位模式,这是否意味着 Java 隐式更改了 t 引用变量的位模式?”目前尚不清楚你的意思是什么。您只是为变量分配一个新值......它与以前的值有什么不同?
  • 编辑试图澄清。我可能只是对引用变量在堆栈上的表示方式有一个误解。
  • 这和垃圾回收没有关系吧?

标签: java pass-by-value


【解决方案1】:

这样想:

Java 没有传递对象,而是传递对象的内存指针。当您创建一个新对象时,它会获得一个新指针。所以当我们说java总是按值传递时,那是因为它总是传递一个数值对象的指针。

即使对象彼此相等 (a.equals(t)) 也可能返回 true - 它们并不相同,因为它们具有不同的指针,因此是驻留在不同内存空间中的不同对象。

使用您的编辑示例。 a 为 0001,但 t 为 0002

Is Java "pass-by-reference" or "pass-by-value"?

希望有帮助

【讨论】:

  • 完美。现在明白了。所以 Java 确实会创建一个新指针和一个新对象,在 switchTo() 方法运行后,它们就有资格进行 GC。
【解决方案2】:

是的,t 的引用将更改为指向新分配的 Test 实例。在这一点上你的理解是正确的。

switchIt() 方法返回时,不再有对该新对象的任何引用。它现在可以进行垃圾回收,而a 继续引用的原始对象在main() 返回之前将无法回收。

【讨论】:

    【解决方案3】:

    我想你明白了,但你的措辞不太好。这是一个更深入的解释,尽管实现可能不是 100% 完全如我所描述的那样。

    当您编译该代码时,将为您的每个方法创建一个称为“堆栈框架”的结构。每个堆栈帧都会为参数、局部变量等提供足够的空间。基本上它会有足够的资源让你的方法去做它的事情。所有这些堆栈帧都放在“堆栈”中:)

    运行代码时,在main 中创建Test 的新实例并将引用分配给变量a,或者更准确地说,分配给为变量a 保留的堆栈帧中的位置。实际对象将存储在堆上,而您的变量 a 将只保存该对象的内存地址,正如您似乎已经知道的那样。

    当您调用switchIt 时,运行时会将引用a 的副本发送到方法switchIt 的堆栈帧。这个堆栈框架有足够的空间来存放你的参数,它将把它存储在它的保留空间中。但是您在switchIt 中所做的是将存储在该保留空间中的初始值替换为来自刚刚创建并放置在堆上的新对象的新引用。现在堆上有两个对象,每个堆栈帧都包含这些引用之一。

    【讨论】:

      【解决方案4】:

      我认为代码会让你更清楚。检查每个打印语句中的哈希码它不是内存位置,但它会帮助你理解你的问题的答案。


      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
          }
      }
      

      Output:

      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()


      注意:哈希码不是实际的内存位置。

      【讨论】:

        猜你喜欢
        • 2010-12-13
        • 1970-01-01
        • 1970-01-01
        • 2011-11-07
        • 2016-03-26
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多