【问题标题】:Passing by reference in JavaJava中的引用传递
【发布时间】:2010-11-27 11:01:49
【问题描述】:

如何在 Java 中通过引用传递一个数组?例如,我需要对数组 A 和 B 执行一些操作并填充数组 C,这应该可供调用者使用。

  public boolean Operate(int[] A, int[] B, int[] C)
  {
     //Write into the empty array C by manipulating values of A and B  and it should be accessible to caller
  }

read 认为与 C# 不同,Java 中不存在按引用传递。在这种情况下,最好的方法是什么。

【问题讨论】:

  • 您将术语“按引用传递”与“通过(对象的引用)按值混淆了我>'。

标签: java


【解决方案1】:

您将术语“按引用传递”与“通过(对象的引用)按值”(其中是没有 out/ref 的 Java 和 C# 所做的)。在上面,如果 A、B 或 C 的内容发生更改,则它们会更改,因为在将它们传递给方法时没有创建/克隆/复制新对象。在 C# 中,'ref' 和 'out' 如何使用 'pass by reference'。请注意,当使用“按引用传递”时,分配给变量会更改调用者传入的变量的值(这在 Java 中是不可能的)。

Wiki: Evaluation Strategies

编辑:如果您真的希望遵循这种方法,请记住调用约定并不规定对象的可变性。考虑以下几点:

void merge(int[] A, int[] B, int[][] C) {
    int[] t = internalMerge(A, B);
    C[0] = t;
}
int[][] icky = new int[1][0];
merge(..., ..., icky);
int[] r = icky[1];

但是,我会更好地构造代码。几乎没有理由使用这种方法,它引入了更多的副作用和状态突变。如您所见,上面的代码已经引入了一个运行时错误。正如其他人所建议的那样,为什么不简单地返回更合适的值呢?

【讨论】:

  • 这里我需要在处理具有值的 A 和 B 之后基于 C 填充。 C 是一个空数组。
【解决方案2】:

在 Java 中,数组是 reference 类型,而不是 value 类型。这意味着数组变量只存储对实际数组的引用

例如,考虑以下代码:

int[] numbers = new int[3];

在本例中,numbers 是对 3 个ints 数组的引用。这可以说明如下:

Java 堆栈 | Java 堆 | |整数数组: +---------+ | +---+---+---+ |数字 |------------->| 0 | 0 | 0 | +---------+ | +---+---+---+ | 0 1 2

现在假设你有一个这样的方法:

public void compute(int[] someValues) {
    someValues[2] = 78;
}

假设您使用 numbers 变量作为参数调用此方法:

int[] numbers = new int[3];
compure(numbers);

在这种情况下,numbers reference按值 传递给 compute。因此,someValuesnumbers 引用副本(不是numbers 引用的数组的副本)。因此,它看起来像这样:

Java 堆栈 | Java 堆 | |整数数组: +---------+ | +---+---+---+ |数字 |------------->| 0 | 0 | 0 | +---------+ | --> +---+---+---+ | / 0 1 2 +------------+ | / |一些值|-----/ +------------+ |

compute返回后,会是这样的:

Java 堆栈 | Java 堆 | |整数数组: +---------+ | +---+---+----+ |数字 |------------->| 0 | 0 | 78 | +---------+ | --> +---+---+----+ | / 0 1 2 +------------+ | / |一些值|-----/ +------------+ |

numbers[2] 将等于someValues[2],因为numberssomeValues 引用同一个数组。

叹气,自从我开始写我的答案以来,这似乎已经得到了类似的回答。希望 ASCII 图表值得保留!

【讨论】:

  • 漂亮的演示。谢谢!
【解决方案3】:

正如你所说,在 Java 中通过引用传递参数是不可能的。

这里有一些解决您的问题的方法:

  1. 如果您已经知道数组 C 应该有多大 - 或者您只是希望该方法对数组进行更改而不重新分配它。那么你的方法就可以正常工作了。 不要分配C变量。
  2. 请参阅 Philip Goh 的回答 - 返回一个数组并检查函数的返回值(null 与否)以替换布尔值。
  3. 如果您不知道数组 C 应该有多大并且想要使用相同的签名 - 请将空的 List<Integer> 传递给函数,然后将其转换为数组。
  4. 您还可以创建一个ReferenceArgument<T> 类,它可以通过以下方式实现:

    public final class ReferenceArgument<T> {
        public T obj = null;
        // You could also make the field private and use getter/setter methods.
    }
    

    但我建议不要这样做 - 但我相信它不适用于数组(不能与泛型很好地混合) - 而且它会装箱原始类型,这有点笨拙。

【讨论】:

    【解决方案4】:

    我假设您从方法中返回一个布尔值来指示成功或失败。

    您可以从函数返回数组 C,而不是返回布尔值。如果 C 为 null,则您知道该函数失败。如果没有,则函数成功。

    【讨论】:

      【解决方案5】:

      所有参数都是按值传递的。但是,在您的情况下,您有一个按值传递的引用(而不是数组中的数据)。这意味着引用被复制并且无法更改,但它引用的数据可以更改。 例如

      // doesn't work because it doesn't change the caller's x and y
      public static void swapReferences(int[] x, int[] y) {
         int[] t = x;
         x = y;
         y = t;
      }
      
      int[] x, y;
      swapReferences(x, y);
      // x and y are unchanged and point to the same arrays with the same data.
      
      // swap the contents
      public static void swapContents(int[] x, int[] y) {
         int[] t = new int[x.length];
         System.arraycopy(x,0,t,0,x.length);
         System.arraycopy(y,0,x,0,x.length);
         System.arraycopy(t,0,y,0,x.length);
      }
      
      swapContents(x, y);
      // x and y are unchanged but the data they refer to has been swapped.
      

      【讨论】:

        【解决方案6】:

        我相信您对术语有些困惑。不用担心。在java中,除了原语之外的所有东西都是通过引用传递的。如果是您的数组,您可以将其填充到您的方法中,并且调用者可以看到更改。

        【讨论】:

        • 调用约定和理解不同的约定在这里很重要。它们是方法内部的 'C = f(A,B)' 不会传播出去的原因。
        【解决方案7】:

        你总是在 java 中传递一个数组通过引用。唯一不通过引用传递(但通过值传递)的对象是原语,int, long, boolean, double, float 等。其他一切都是对象并通过引用传递。所以你的代码可以正常工作。

        编辑:我谦虚地承认我的愚蠢错误。你总是在java中传递。但是对象总是以 reference 作为值传递

        【讨论】:

        • 调用约定和理解不同的约定在这里很重要。它们是方法内部的 'C = f(A,B)' 不会传播出去的原因。
        • 好的,我的立场是正确的。它将引用作为值传递
        猜你喜欢
        • 1970-01-01
        • 2011-11-10
        • 1970-01-01
        • 1970-01-01
        • 2021-11-04
        • 2013-07-22
        • 2011-05-02
        • 2012-03-13
        相关资源
        最近更新 更多