【问题标题】:Java Memory, Pass-by-Value, Pass-by-Reference [duplicate]Java内存,按值传递,按引用传递[重复]
【发布时间】:2012-03-13 00:35:00
【问题描述】:

可能重复:
Is Java pass by reference?

我有一个关于在 java 中按值传递和按引用传递的问题。

我编写了一个“Graph”类,用于将一长串双精度数显示为图形,(简化的)构造函数如下所示。

private double[] Values;

public Graph(double[] values) {
   Values = values;
}

数组可以很长并且占用合理的内存量。

基本上我的问题是:如果我调用构造函数来创建一个新图,数组“Values”是传递给它的数组的副本,还是引用?

在我看来,基元是“按值传递”,对象是“按引用传递”,这应该意味着数组是一个副本。虽然我知道这个定义在技术上并不正确。

如果我是正确的,并且数组是一个副本,那么减少该类使用的内存量并从另一个类引用该数组的最佳方法是什么? 抽象的 GetValues() 方法会是实现此目的的好方法吗?

提前致谢,

克里斯。

【问题讨论】:

  • Java“按值传递引用”。
  • 如果您想考虑 java 传递低级 c 术语,最合适的是 const Object* - 指向常量对象的指针。最好不要引用引用 - 这只是令人困惑,因为它已经在 c++ 术语中定义,并且与 java 所做的完全不同。
  • 感谢您解决这个问题。我知道这不是一个正确的定义,但现在我知道了正确的方法。谢谢

标签: java pass-by-reference pass-by-value


【解决方案1】:

它将是values 的引用。 Java 是传值,但传值的是对数组的引用,因为数组是一个对象。

另请参阅几天前的 this answer

【讨论】:

    【解决方案2】:

    这将是一个参考。参数values被“按值引用”传递,引用附加到Values

    因此 - 对Graph.Value 的任何更改也将反映到values,反之亦然。

    【讨论】:

      【解决方案3】:

      Java 是按值传递,句号。

      JLS4.12.3 Kinds of Variables

      方法参数(第 8.4.1 节)名称参数值传递给一个方法。对于方法声明中声明的每个参数,每次调用该方法时都会创建一个新参数变量(第 15.12 节)。使用方法调用中的相应参数值初始化新变量。当方法体的执行完成时,方法参数实际上不再存在。

      编辑:澄清我的回答:Java 的类型分为两类:原语类型和引用类型。每当您调用方法(或构造函数)时,都会复制参数(因为 Java 是按值传递的)。原语被完全复制,对于引用类型,引用被复制。 Java 永远不会自动对任何内容进行深度复制,因此由于数组是引用类型,因此只会复制对数组的引用。

      【讨论】:

      • 你可以说对象的引用是按值传递的。这具有对象本身通过引用传递的效果。
      • @phlogratos 是这样吗?然后请写一个swap(Object a, Object b) 方法。这基本上是通过引用的试金石。
      • -1。您没有回答基本问题“如果我调用构造函数,数组是副本还是引用?”,但暗示答案是“副本”,这是错误的(即使您的答案是技术上正确)。它正在复制引用,而不是数组。
      • 这仅适用于简单的 Java Bean,与引用调用无关。它尤其不适用于IntegerStringBoolean、...等不可变类型和Lists、...等复杂类型。
      • @phlogratos Umn.. 如果您认为这是一种交换方法,您应该真正查看 copyProperties 的作用。或者更简单——想想所有那些没有空构造函数的类。
      【解决方案4】:

      double 是原始类型,double[] 是 Object 类型(数组),所以,不,整个数组不会传递给构造函数,而是将数组作为“引用的值”传递”。您将无法替换构造函数中的数组,但如果需要,您可以替换数组中的各个值。

      【讨论】:

      • 请注意,它仍然不是引用。如果你通过引用传递东西,我们可以实现一个交换方法。这在java中根本不起作用..
      • 是的,自然是“按值引用”
      • 好的,那么您将“引用”用作指针的同义词。这就是我们在这里重用定义完全不同的术语的问题,叹息。
      • @Voo Java 术语是“参考”,而不是“指针”。你不能做指针算术。它并不指向内存中的某个点。 GC 可以在内存中移动对象,而无需更新引用。
      【解决方案5】:

      数组是一个引用类型,通过副本传递只适用于原始类型,而数组不是。顺便说一下,其他引用类型包括接口

      【讨论】:

        【解决方案6】:
        // Points:
        // 1) primitive variables store values
        // 2) object variables store addresses(location in the heap)
        // 3) array being an object itself, the variables store addresses again (location in the heap)
        
        // With primitives, the bit by bit copy of the parameters, results in the
        // value being copied. Hence any changes to the variable does not propagate
        // outside
        void changePrimitive(int a) {
            a = 5;
        }
        
        // With objects, the bit by bit copy of the parameters, results in the address
        // begin copied. Hence any changes using that variable affects the same object
        // and is propogated outside.
        class obj {
            int val;
        }
        void changeObject(obj a) {
            a.val = 10;
        }
        
        // Array is itself an object which can hold primitives or objects internally.
        // A bit by bit copy of the parameters, results in the array's address
        // being copied. Hence any changes to the array contents reflects in all 
        // the locations having that array. 
        void changeArray(int arr[]) {
            arr[0] = 9;
            arr[1] = 8;
        }
        
        // NOTE: when object/array variable is assigned a new value, the original
        // object/array is never affected. The variable would just point to the
        // new object/array memory location.
        void assignObj(obj a) {
            a = new obj();
            a.val = 10;
        }
        

        【讨论】:

          猜你喜欢
          • 2013-12-02
          • 2012-03-12
          • 2013-09-15
          • 2014-09-10
          • 2011-05-16
          • 2019-05-07
          • 2023-03-07
          • 2013-01-21
          • 1970-01-01
          相关资源
          最近更新 更多