将数组传递给方法与将原始数据类型传递给方法不一致
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 中其他对象的行为方式尽可能一致。
我 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 中其他对象的行为方式尽可能一致。