为什么Java中的这个函数不会影响结果?

时间:2013-05-23 15:33:00

标签: java arrays function methods

class Test {
    public static void main(String[] args) {
        int[] list = {1, 2, 3, 4, 5};
        reverse(list);
        for (int i = 0; i < list.length; i++) {
            System.out.print(list[i] + " ");
        }
   }

   public static void reverse(int[] list) {
       int[] newList = new int[list.length];

       for (int i = 0; i < list.length; i++) {
           newList[i] = list[list.length - 1 - i];
       }

       list = newList;
   }
}

当我运行这个程序时,答案是1 2 3 4 5.这个'反向'方法在第4行被调用。

5 个答案:

答案 0 :(得分:4)

您必须return新列表,而不是修改参数引用,因为它只是方法范围。

class Test {
    public static void main(String[] args) {
        int[] list = {1, 2, 3, 4, 5};
        list = reverse(list);
        for (int i = 0; i < list.length; i++) {
            System.out.print(list[i] + " ");
        }
   }

   public static int[] reverse(int[] list) {
       int[] newList = new int[list.length];

       for (int i = 0; i < list.length; i++) {
           newList[i] = list[list.length - 1 - i];
       }

       return newList;
   }
}

答案 1 :(得分:3)

list = newList;

您刚刚更改了local参数以引用新的数组实例。

这不会影响调用者的变量,它仍然引用您传递的原始数组实例。

答案 2 :(得分:2)

这是因为您按值传递list。即行list = newList对呼叫者没有影响。在Java中,一切都按值传递。

要做你想做的事,把你的功能改为

public static int[] reverse(int[] list)

并在你的功能结束时。

return newList;

而不是

list = newList;

更正式地说,对数组的引用是按值传递的。当您重新分配list = newList时,您将引用指向另一个数组。但是在调用者中引用没有改变,因此指向原始数组。

答案 3 :(得分:1)

问题是Java参数传递是按值传递的。 reverse的最后一个陈述是:

    list = newList;

不幸的是,由于list是一个参数(并按值传递),因此此分配不会影响list方法中main的值。

要使reverse方法正常工作:

  • 将其更改为返回反转列表(并将结果分配到list中的main)或
  • 更改它以从list的相应单元格中指定newList的单元格。

(顺便说一句,如果您要更新list,可以在没有单独的newList数组的情况下进行更新。)


回应此评论:

  

我正在阅读的书中说,数组是通过引用传递的,并且方法中数组发生的任何事情都会影响main方法中的原始数组。或许我解释错了!

这本书是错的,或者你误解了它。 (我怀疑可能是后者。)Java中的所有类型(即所有类型)都是按值传递的,并按值返回。

有点令人困惑的是,在引用类型的情况下,传递或返回的值是对象的引用。这留下了误解术语的空间(或者书籍有点草率)但是......

  

“通过参考传递

......和......

  

“传递 a 参考”

......并不意味着同样的事情。

(事后看来,Gosling等人决定调用Java对象指针“引用”是新Java程序员混淆的一个原因.OTOH,如果程序员从C和C ++过渡,那么会有一种不同的混淆旧词“指针”。)

答案 4 :(得分:1)

问题是,Java按值传递对数组的引用。也就是说,引用reverse正在修改的不是调用者的版本,而是仅为此调用创建的副本。来电者永远不会看到重新分配。

最终结果是您可以根据需要修改数组,但不能以调用者看到的方式使用不同的数组替换它。在Java中没有办法做到这一点,没有创建包装类。

您可以通过在完成后将新阵列复制到旧阵列中来实现您正在寻找的结果。即:而不是

list = newList;

DO

System.arraycopy(newList, 0, list, 0, list.length);

如果您确定总是希望它修改原始数组,您也可以将其反转:

public static void reverse(int[] list) {
    for (int i = 0, j = list.length - 1; i < j; ++i, --j) {
         int temp = list[i];
         list[i] = list[j];
         list[j] = temp;
    }
}

这可以避免创建一个你要丢弃的对象。

但是,如果您预计只想要一个反向的副本数组,而不是总是修改您给出的那个,那么最好还是返回新数组并让调用者决定如何处理它。