Java中的参数传递

12

我知道Java始终是按值传递的,但是我不明白为什么这样可以工作:

public static void swap(int[] arr, int i, int j)
{
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static void main(String[] args)
{
    int[] arr = {3, 4, 5, 6};
    swap(arr, 1, 3);
    // arr becomes {3, 6, 5, 4}
}

这样不起作用:

public static void swap(int[] arr, int[] arr2)
{
    int[] tmp = arr;
    arr = arr2;
    arr2 = tmp;
}
public static void main(String[] args)
{
   int[] arr = {3, 4, 5, 6};
   int[] arr2 = {1, 2, 5, 6};
   swap(arr, arr2);
}

为什么?


你需要理解引用。 - Thorbjørn Ravn Andersen
1
可能是Java是按引用传递还是按值传递?的重复问题。 - user719662
1
Java通过值传递引用 - Boris the Spider
5个回答

14

第二种方法试图交换引用,但这不起作用,因为引用本身是按值传递的。

第一种方法是正确的,因为它改变了数组引用的对象(可变),而不是改变引用本身。

查看这篇博客文章以获取有关按值传递和按引用传递之间差异的更多详细信息。


我还要补充一点,Java中的数组是可变的,这就是为什么第一个示例可以工作的原因。 - Alexey Malev

7
你的第一个示例是传输数组中的值。
第二个示例中,你试图交换引用(在Java中,数组是对象)。这些引用是局部副本(按值传递),并且对调用方上下文没有影响。
(关于按值调用的问题#56.903;Stackexchange应该开放PassByValue.com;-)

3
如果您曾经使用过C或C++并且了解指针的工作原理,那么让我深有感触的是以下陈述:
In Java, everything is passed by value. 
In case of Objects, the reference (pointer) is passed by value.

所以基本上,这是关于swap函数的。
public void swap(int[] a, int[] b)
{
    etc.
}

我将只获取指向a int[]数组和指向b int[]数组的指针。

您只是交换了两个指针。您不能像那样修改指针的内容。

基本上,这相当于C语言的操作。

void swap(int* a, int* b)
{
   int* temp = a;
   a = b;
   b = temp;
}

int main(void)
{
    int a[] = {5,6,7,8};
    int b[] = {1,2,3,4};
    swap(a,b);
}

即使在C语言中,这也只能像这样工作:

void swap(int** a, int** b)
{
   int* temp = (*a);
   (*a) = (*b);
   (*b) = temp;
}

int main(void)
{
    int a[] = {5,6,7,8};
    int b[] = {1,2,3,4};
    swap(&a, &b);
}

当然,在Java中你无法发送引用的引用。在这个意义上,指针在Java中不存在。
因此,为了实际修改另一个函数中的对象,你需要一个“Holder”对象来复制引用,但其中对你想要修改的对象的引用实际上是该对象的真实引用,如果这有意义。
因此,下面的内容可以起作用:
public class ArrayHolder
{
    public int[] array;

    public ArrayHolder(int[] array)
    {
        this.array = array;
    }
}

public void swap(ArrayHolder a, ArrayHolder b)
{
    int[] temp = a.array;
    a.array = b.array;
    b.array = temp;
}

public static void main(String[] args)
{
    ArrayHolder aaa = new ArrayHolder(new int[] {5,6,7,8});
    ArrayHolder bbb = new ArrayHolder(new int[] {1,2,3,4});
    swap(aaa,bbb);
}

1
  • 第一个交换,你改变了数组的数据(由引用arr引用),所以它被修改了。

  • 第二个交换,你改变了arr、arr2两个本地变量。因此,当你退出方法时,这两个新变量就会被销毁。


1
  • Arrarr2 是局部变量,因此当交换方法完成时,它们将被销毁。
  • 在交换方法之外,局部变量的更改不会受到影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接