在Java中通过引用传递

时间:2010-11-27 11:01:50

标签: java

如何在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
  }

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

7 个答案:

答案 0 :(得分:3)

你得到的术语'通过引用传递'与'传递(对象的引用)按值'(其中是什么Java和C#,没有out / ref做什么)。在上文中,如果A,B或C的内容被改变,则它们被改变,因为当它们被传递给该方法时没有新的对象被创建/克隆/重复。在C#中,'ref'和'out'如何使用'按引用传递'。请注意,当使用'按引用传递'时,分配给变量会更改调用者传入的变量值(这在Java中是不可能的)。< / p>

请参阅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];

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

答案 1 :(得分:3)

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

例如,请考虑以下代码:

int[] numbers = new int[3];

在此示例中,numbers是3个int s数组的引用。这可以说明如下:

    Java Stack       |         Java Heap
                     |
                     |       Array of ints:
   +---------+       |       +---+---+---+
   | numbers |-------------->| 0 | 0 | 0 |
   +---------+       |       +---+---+---+
                     |         0   1   2

现在假设您有这样的方法:

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

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

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

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

    Java Stack       |         Java Heap
                     |
                     |       Array of ints:
   +---------+       |       +---+---+---+
   | numbers |-------------->| 0 | 0 | 0 |
   +---------+       |   --> +---+---+---+
                     |  /      0   1   2
   +------------+    | /
   | someValues |-----/
   +------------+    |

compute返回后,它将如下所示:

    Java Stack       |         Java Heap
                     |
                     |       Array of ints:
   +---------+       |       +---+---+----+
   | numbers |-------------->| 0 | 0 | 78 |
   +---------+       |   --> +---+---+----+
                     |  /      0   1   2
   +------------+    | /
   | someValues |-----/
   +------------+    |

numbers[2]将等于someValues[2]因为numberssomeValues 引用相同的数组。

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

答案 2 :(得分:2)

正如你所说,在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.
    }
    

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

所有参数都按值传递。但是在您的情况下,您有一个通过值传递的引用(而不是数组中的数据)。这意味着引用被复制并且不能更改,但可以更改引用的数据。 e.g。

// 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.

答案 5 :(得分:-1)

我相信你对术语有点困惑。别担心。在java中,除了基元之外的所有内容都通过引用传递如果是您的阵列,您可以在您的方法中填写它,并且调用者可以看到更改。

答案 6 :(得分:-1)

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

编辑:我谦卑地承认我的愚蠢错误。您始终在java中通过值传递。但是对象总是以引用作为值传递。