请解释这个 Java 数组参考参数传递行为

Posted

技术标签:

【中文标题】请解释这个 Java 数组参考参数传递行为【英文标题】:Please Explain this Java Array Reference Parameter Passing Behavior 【发布时间】:2013-07-10 09:22:33 【问题描述】:
public class TestArray 
    public static void main(String[] args) 
        int[] ar = 1,2,3,4,5,6,7,8,9;

        shiftRight(ar);
        for (int i = 0; i < ar.length; i++) 
            System.out.print(ar[i]);
        
        // prints: 912345678 -- good
        System.out.println();

        reverseArray(ar);
        for (int i = 0; i < ar.length; i++) 
            System.out.println(ar[i]);
        
        // prints: 91234567 -- I don't understand       
        System.out.println();       
    
    public static void shiftRight(int[] ar) 
        int temp = ar[ar.length - 1];
        for (int i = ar.length - 1; i > 0; i--) 
            ar[i] = ar[i - 1];
        
        ar[0] = temp;
    
    public static void reverseArray(int[] ar) 
        int[] temp = new int[ar.length];
        for (int i = 0, j = temp.length - 1; i < ar.length; i++, j--) 
            temp[i] = ar[j];
        
        ar = temp;
        for (int i = 0; i < ar.length; i++) 
            System.out.print(ar[i]);
        
        // prints: 876543219
        System.out.println();
    

将数组传递给参数会导致将数组的引用传递给参数;如果在方法内更改了数组参数,则该更改将在方法外可见。

第一个方法shiftRight 完成了我的预期:它改变了方法之外的数组。

但是,第二种方法不会更改方法之外的数组。但是在方法内部运行 for 循环会打印正确的值。为什么ar 的引用不指向temp?是因为当方法停止时变量temp 被破坏了——这是否也会杀死引用?即便是这样,为什么Java要取ar,它被指向temp的引用,然后重新应用到ar的原始引用?

谢谢。

【问题讨论】:

【参考方案1】:

问题是您创建了一个局部变量temp 数组,并设置了ar=temp。您需要实际修改ar 的内容,而不是创建一个新的本地数组并将您复制的ar 变量指向temp

Try something like this.

public static void reverseArray(int[] ar) 
    int[] temp = new int[ar.length];
    System.arraycopy( ar, 0, temp, 0, ar.length );
    for (int i = 0, j = temp.length - 1; i < ar.length; i++, j--) 
        ar[i] = temp[j];
    

    for (int i = 0; i < ar.length; i++) 
        System.out.print(ar[i]);
    
    // prints: 876543219
    System.out.println();

【讨论】:

【参考方案2】:

reverseMethod 接收到自己对数组的引用,并且无法触及调用者的引用。

换句话说,它通过值接收引用;如果它选择在保存它的局部变量中存储一个新值,那很好,但它对可能存储对旧值的引用的其他地方没有影响。

【讨论】:

【参考方案3】:

在 Java 中,说对象通过引用传递是一种用词不当。更准确的说法是对对象的引用是按值传递的。

您将数组引用按值传递给reverseArray。 local 参数是对数组的引用的副本。以后当你说

ar = temp;

您仅将 local ar 指向 temp,而不是来自 main 的原始数组引用 ar

另一方面,在shiftRight方法中,您已经通过复制的引用直接访问了数组,因此原始数组的内容发生了变化,并且该方法按预期工作。

【讨论】:

因此,虽然传递给参数的值是对数组的引用,但参数本身是它唯一的变量(最初指向同一个引用),当指向本地数组时不指向该引用的外部变量? 是的。 Java 中的所有参数传递都是如此。 是的,ar = temp 将您的本地 ar 引用分配给 temp 引用的数组。 @Michal 我知道原始值就是这种情况,但将引用与数组的变量混为一谈。 有关Java如何传递参数的更多信息,请参阅Is Java “pass-by-reference”?。【参考方案4】:

当你将 temp 的值赋给 ar 时

ar = temp;

您将方法参数的指针设置为该值,这不会以任何方式修改主方法中 ar 的引用。

如果您希望您的修改“坚持”,则从该方法返回值并在 main 中分配它,如下所示:

public static void main(String[] args) 
    int[] ar = 1,2,3,4,5,6,7,8,9;

    ar = reverseArray(ar);
    System.out.println();       


public static int[] reverseArray(int[] ar) 
    int[] temp = new int[ar.length];
    for (int i = 0, j = temp.length - 1; i < ar.length; i++, j--) 
        temp[i] = ar[j];
    
    ar = temp;
    for (int i = 0; i < ar.length; i++) 
        System.out.print(ar[i]);
    
    // prints: 876543219
    System.out.println();

    return ar;  // might as well return temp

【讨论】:

以上是关于请解释这个 Java 数组参考参数传递行为的主要内容,如果未能解决你的问题,请参考以下文章

spring MVC 怎么获取前端传递的数组参数

为啥数组不能作为函数参数传递?

cordova.exec 参数中的奇怪行为

实现数组元素互换位置(乘机理解java参数传递)

Django给echarts传递参数的问题?

Java8-通过行为参数化传递代码