将数组传递给方法与将原始数据类型传递给方法不一致

Passing Arrays to a method inconsistent with passing primitive data type to a method

understand 将数组传递给方法仍然是 Pass-By-Value,但是传递的 "value" 是 数组的引用。这意味着更改数组的内容会导致内容在较早的帧中得到更新(如果它是递归算法),或者当它返回到 main 方法时,就此而言。

import java.util.Arrays;

public class SameArrayPassedOn{
    public static void main(String[] args) {
        int[] a = {1,1,1};

        print(a);
        fun(a,0);
        print(a);
    }

    static void fun(int[] b, int count)
    {
        if(count == 1)
            return;

        b[0] = b[1] = b[2] = 2; 
        fun(b,1);
    }

    static void print(int[] a)
    {
        for(int x : a)
            System.out.print(x + " ");
        System.out.println("");
    }
}

Output 111 222

但是,如果您创建一个新数组,例如在下面的代码中,由于引用已更改,因此当您返回到 main 方法时,更新将不会反映出来。

import java.util.Arrays;

public class NewArrayCreatedAndReferencePassedOn{
    public static void main(String[] args) {
        int[] a = {1,1,1};

        print(a);
        fun(a,0);
        print(a);
    }

    static void fun(int[] b, int count)
    {
        if(count == 1)
            return;

        int[] newb = {2,2,2};
        fun(newb,1);
    }

    static void print(int[] a)
    {
        for(int x : a)
            System.out.print(x + " ");
        System.out.println("");
    }
}

Output 111 111

但是,我的问题是,为什么为数组选择了这样的设计。为什么不能那样,就像原始数据类型一样,比如整型变量,每次在函数内部传递时都会创建一个新的 int,尽管我们没有明确创建或声明一个新的 int。例如,

import java.util.Arrays;

public class SameIntPassedOn_ButNewCopyCreatedEachFrame {
    public static void main(String[] args) {
        int i = 0;

        fun(i);
    }

    static void fun(int b)
    {
        System.out.println(b);

        if(b == 10)
            return;

        b = b+1;
        fun(b);

        System.out.println(b);
    }
}

输出

0 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1

如果对数组也做同样的事情,它会让我们为递归函数的每一帧都有一个不同的数组副本,这会非常方便。

我认为在行为上具有统一性会很好,因为目前看来,要使用数组实现相同的行为,就像原始数据类型(如 int、float)所展示的那样等,当传递给方法时,需要使用'new'关键字,并在传递给方法之前创建一个新数组。

数组是一个包含一组对象的容器(数据结构)。

这些物体可大可小。数组可以包含很多对象

想象一下我们对每个数组引用进行完整复制

语言将极其缓慢且效率低下

所以主要原因是效率

答案是所有对象,实际上所有方法参数都是按值传递的。您的评估 "Had the same been done for arrays" 是错误的,因为数组也是如此。与所有对象引用一样,数组按值传递。发送到方法的原始值的副本与调用者传递的值相同。发送到方法的数组指针的副本与调用者传递的值相同。发送给方法的任何对象指针的副本与调用者传递的值相同。 它指向同一个对象,因为指针是按值复制的。

为什么,你问?因为它简单,有效,而且真的没有缺点。

However, my question is, why such a design was chosen for Arrays.

有几个主要原因。

首先是性能 - 如果每次调用方法时都必须创建数组的新副本,这将导致性能极差,尤其是对于递归调用。

Had the same been done for arrays, it would've allowed us to have a different copy of the array for each frame of the recursive function, which would've been very handy.

第二个是,如果您愿意,您已经可以选择传递数组的副本 - 您可以手动创建一个副本并传递它。这样程序员拥有最大的控制权——他们可以选择让方法调用修改数组,或者他们可以选择传递一个副本,允许每个方法调用它的数组版本来使用。如果我们强迫程序员一直使用副本,他们将失去让方法调用修改数组的选项,这在某些情况下非常有用。目前的设计给了程序员最多的选择。

Why couldn't it be that, just like for a primitive data type...

最后一个原因是数组不是原始数据类型——它是一个对象。最有可能做出的决定是使数组与 Java 中其他对象的行为方式尽可能一致。