【问题标题】:Changing array in method changes array outside [duplicate]更改方法中的数组会更改外部的数组[重复]
【发布时间】:2014-03-06 08:35:53
【问题描述】:

我对变量范围有疑问。

public static void main(String[] args){
    int[] test={1,2,3};
    test(test);
    System.out.println(test[0]+" "+test[1]+" "+test[2]);
}

static void test(int[] test){
    test[0]=5;
}

我希望输出为1 2 3,但结果是5 2 3。 为什么我在方法中改变了数组中的值,而原来的数组却改变了?

【问题讨论】:

  • 因为你正在修改对象的状态...
  • 不要被参数名弄糊涂了。在 test(..) 方法中将参数名称更改为 whatever,它不会影响任何内容。
  • 致 OP:这与范围无关。您将对象引用值传递给方法,并通过方法内的该引用修改对象。这就是Java(和C,以及......)的工作方式。见:Oracle tutorial on the subject
  • @SotiriosDelimanolis 将按值传递,如果您考虑一下(我的意思是,考虑仅传递数组的值),那将是正确。但是您改为传递引用的副本,因此如果您更改对象的状态(在本例中为数组中的条目),那么 original 对象也将被修改。跨度>
  • int[] temp=test 不会创建新的数组对象,它只是将数组引用(即指针)从“test”复制到“temp”。

标签: java variables scope


【解决方案1】:

Java 中的数组是一个对象。当您通过new 创建一个数组时,它会在堆上创建,并返回一个引用值(类似于C 中的指针)并分配给您的变量。

在 C 中,这将表示为:

int *array = malloc(10 * sizeof(int));

当您将该变量传递给一个方法时,您传递的是分配(复制)给该方法中的本地(堆栈)变量的引用值。数组的内容没有被复制,只有参考值。同样,就像在 C 中传递指向函数的指针一样。

因此,当您通过该引用修改方法中的数组时,您正在修改堆上存在的单个数组对象。

您评论说您再次通过int[] temp=test 制作了数组的“副本”...,这只制作了指向内存中单个数组的引用值(指针)的副本。您现在拥有三个变量,它们都持有对同一个数组的相同引用(一个在您的 main() 中,两个在您的方法中)。

如果要复制数组的内容,Java 提供了static method in the Arrays class

int[] newArray = Arrays.copyOf(test, test.length); 

这会在堆上分配一个新数组对象(大小由第二个参数指定),将现有数组的内容复制到它,然后将对该新数组的引用返回给您。

【讨论】:

  • 说 OP 的 test 方法包含 test = new int[] {7, 7, 7},本质上是创建一个新数组并将指针重定向到该数组。为什么这一次,外面的数组没有变化?
【解决方案2】:

定义:

  • Reference = 指向数组所在内存位置的变量。
  • 引用值 = 实际内存地址位置本身

您将数组引用的值传递给您的test() 方法。由于 java 是按值传递,它传递引用的值,而不是数组的值(即副本)。

如果您有 C 背景,将引用视为指针可能更容易。所以引用的值本质上是它的内存地址(我在这里捏造了 java 规则,但这样想可能是最简单的)

因此,在您的示例中,您将指向您的数组的引用的值传递给您的 test() 方法,然后该方法使用该引用值来查找您的数组在内存中的位置,因此它可以访问你的阵列。

由于在您的test() 方法中您没有更改数组的引用(它指向的位置,即test = new int[10];),那么您的test() 方法将作用于数组中的原始数据(因为它仍然指向原始数组的位置),导致元素 0 被设置为值 5

【讨论】:

  • 每当有人说按值传递“令人困惑”时,我都会感到困惑。 C 按值传递指针。 Java 做同样的事情。
  • 更混乱?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-20
  • 2018-09-20
  • 1970-01-01
  • 2021-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多