为什么当我传递一个数组时,它会改变方法中的值?惊人

时间:2011-12-12 03:10:00

标签: java

public class Test {
    public static void main(String[] args) {
        int[] arr = new int[5];
        arr[0]    = 1;
        method(arr);
        System.out.println(arr[0]);
    }

    private static void method(int[] array)
    {
        array[0] = 2;
    }
}

调用方法后,arr[0]变为2.为什么会这样!?

7 个答案:

答案 0 :(得分:3)

您可以在传递给方法的对象上调用set方法。 Java是按值传递的,这意味着您无法替换方法中的对象,但可以在对象上调用set方法。

如果Java通过引用传递,则会传递:

public class Test {

public static void main(String[] args) {
    Test test = new Test();
    int j = 0;
    test.setToOne(j);
    assert j == 1;
}

public void setToOne(int i) {
    i = 1;
}
}

答案 1 :(得分:1)

这是因为Java在将参数传递给方法时使用Call by Object-Sharing *(对于非基本类型)。

当您传递一个对象(包括数组)时,您传递对象本身未创建副本。

如果你在一个地方改变对象,比如在被调用的方法中,你可以在任何地方改变对象! (因为对象本身是: - )

以上是上面的代码,注释:

public static void main(String[] args)
{
    int[] arr = new int[5]; // create an array object. let's call it JIM.
    // arr evaluates to the object JIM, so sets JIM[0] = 1
    arr[0]    = 1;          
    System.out.println(arr[0]);  // 1
    method(arr);                 // fixed typo :-)
    // arr still evalutes to JIM
    // so this will print 2, as we "mutated" JIM in method called above
    System.out.println(arr[0]);  // 2
}

private static void method(int[] array)
{
    // array evaluates to the object JIM, so sets JIM[0] = 2
    // it is the same JIM object
    array[0] = 2;
}

快乐的编码。


*原始值始终具有按值调用的语义 - 即,有效地创建副本。由于所有原始值都是不可变的,因此不会产生冲突。

另外,正如Brian Roach所指出的那样,JVM只在内部实现了call-by-value:上面讨论的call-by-object-sharing语义是通过传递值的引用来实现的。给定的对象。如链接的维基百科文章所述,用于描述此行为的特定术语因编程社区而异。


其他:

  1. Pass by value or Pass by reference in Java? - 请参阅aioobes的回答以及它与Brian Roachs评论的关系。再次aioobe:Does array changes in method?

  2. Make copy of array Java - 请注意,这只会创建一个“浅层”副本。

答案 2 :(得分:1)

答案 3 :(得分:0)

因为这正是你要告诉它的事情。 Java先通过值传递,然后通过引用传递。您正在传入数组,但您对该数组所做的任何修改都将反映在对该数组的任何其他访问中。

思考的一个简单例子:

如果在method array = null范围内main,则array不会显示任何更改 - 因为您将更改{{1}}的本地值而不修改引用中的任何内容

答案 4 :(得分:0)

method(arr[0]);

我认为那应该是

method(arr);

但无论如何,作为参数传递给方法的值是对数组的引用,并且方法中的局部变量 arr引用相同的数组。因此,在该方法中,您要对同一个数组进行更改。

答案 5 :(得分:0)

因为当您传递诸如int / double / char之类的参数时,它们是原始数据类型并且它们是按值调用的 - 这意味着它们的值被复制到此方法中的局部变量(其名称与您的参数中的名称)以及对它们所做的更改只是对这些本地var的更改 - >不会影响方法

之外的原始类型变量

然而,通过引用调用数组或任何对象数据类型 - >参数将其地址(引用)传递给方法。这样,你仍然有一个由它们命名的局部变量,它具有引用。您可以将其更改为引用另一个数组或任何内容。但是当它引用一个数组时,你可以用它来设置数组的值。它的作用是访问它引用的地址并更改引用位置的内容

答案 6 :(得分:0)

Java是按值传递的。令人困惑的是,引用堆上分配的对象的变量的'value'是一个引用,所以当你传递它时,你传递引用'by value',因此它引用堆上的同一个对象。这意味着修改指示对象的位置无关紧要;你正在改变同样的事情。