Equated Java Arrays中的奇怪之处:引用与指针

有一个问题,了解下面的代码发生了什么。 数组cd的行为是我所期望的。 但是ab什么? (我也尝试使用普通的标量变量,在任何一种情况下都不会发生任何意外。)

输出将复制到RH注释。

 import java.util.Arrays; public class ArraysParadox { public static void main(String[] args) { int[] c = {1, 2, 3}; int[] d = {6, 5, 4, 3}; System.out.print("c: "); System.out.println(Arrays.toString(c)); // c: [1, 2, 3] System.out.print("d: "); System.out.println(Arrays.toString(d)); // d: [6, 5, 4, 3] System.out.println("--- swap ---"); int[] tmp = c; c = d; d = tmp; // <----- Magic? System.out.print("c' (=d): "); System.out.println(Arrays.toString(c)); // c' (=d): [6, 5, 4, 3] System.out.print("d' (=c): "); System.out.println(Arrays.toString(d)); // d' (=c): [1, 2, 3] System.out.println("--- c = 0 ---"); Arrays.fill(c, 0); System.out.print("c (=0): "); System.out.println(Arrays.toString(c)); // c (=0): [0, 0, 0, 0] System.out.print("d (=c): "); System.out.println(Arrays.toString(d)); // d (=c): [1, 2, 3] System.out.println("--- d = 1 ---"); Arrays.fill(d, 1); System.out.print("c (=d): "); System.out.println(Arrays.toString(c)); // c (=d): [0, 0, 0, 0] System.out.print("d (=1): "); System.out.println(Arrays.toString(d)); // d (=1): [1, 1, 1] System.out.println("================"); int[] a = {1, 2, 3}; int[] b = {6, 5, 4, 3}; System.out.print("a: "); System.out.println(Arrays.toString(a)); // a: [1, 2, 3] System.out.print("b: "); System.out.println(Arrays.toString(b)); // b: [6, 5, 4, 3] a = b; System.out.print("a (=b): "); System.out.println(Arrays.toString(a)); // a (=b): [6, 5, 4, 3] System.out.println("--- α = 0 ---"); Arrays.fill(a, 0); System.out.print("a (=0): "); System.out.println(Arrays.toString(a)); // a (=0): [0, 0, 0, 0] System.out.print("b (=a?): "); System.out.println(Arrays.toString(b)); // b (=a?): [0, 0, 0, 0] ??? System.out.println("--- b = 1 ---"); Arrays.fill(b, 1); System.out.print("b (=1): "); System.out.println(Arrays.toString(b)); // b (=1): [1, 1, 1, 1] System.out.print("a (=b?): "); System.out.println(Arrays.toString(a)); // a (=b?): [1, 1, 1, 1] } } 

cd的可交换性表示根据这篇文章的传值: Java是按值传递,该死! 。 (我也看了一下java数组通过引用传递不起作用?但是我无法理解提问者的英文,而方法调用模糊了这个例子。)

请注意,使用d = tmp; 注释掉, cd表现出与ab相同的奇怪行为。 我仍然不知道该怎么做。

任何人都可以解释ab的行为如何通过传值来解释?

编辑:附录

事实certificate,我的post中的主要问题不是传值,而是别名。 为了清楚传值和指针之间的区别,我在代码中添加了以下方法,并用它来(尝试)交换cd (由JavaDude上面链接的文章链接的文章建议)。

 static  void swap (T c, T d) { T tmp = c; c = d; d = tmp; } 

结果是cd保持不变。 如果Java(如C)将指向cd指针传递给方法,那么这将起作用,而是简单地传递它们的值,保持原始变量不变。

a = b更改为a = b.clone(); 或者a = Arrays.copyOf(b, b.length); 给出了我期待的行为。 此代码也有效:

  int[] tmp = new int[b.length]; System.arraycopy( b, 0, tmp, 0, b.length ); a = tmp; 

相对时间在这里描述 。

这里没有什么“怪异”:数组变量是实际数组的引用 (在其他语言中也称为指针)。 操作数组变量时,所有操作都是操作指针。

将数组变量分配给另一个变量时,可以为分配的变量指向的数组创建别名 ,并使分配的变量先前指向的数组符合垃圾回收的条件。 因为赋值a = b构成a = b的别名,所以用数据填充b与填充数据完全相同:一旦赋值完成, ab只是同一事物的两个不同的名称。

传递值而言,在您的示例中没有任何内容:只有当您将对象作为参数传递给您调用的方法时,传递值的概念才适用。 在您的示例中,变量abcd不是方法参数,它们是局部变量。 你通过引用方法toStringfill来传递它们(或者更确切地说,你将对象的引用传递给toStringfill ,因为在Java中,所有内容都是通过值传递的),这就是为什么通过fill完成对数组的修改从方法返回时可见。

当你做出a = b;的任务时a = b; ,如果ab不是基元,那么它们现在引用相同的对象。 在您的情况下,他们现在引用相同的数组。 你对任何一个做出的任何改变也会影响另一个(因为你只更新了一件事, ab都指向它)。

请注意,此行为与参数在Java中的传递方式无关。

数组初始化程序在引擎盖下调用new(所以在这种情况下它是语法糖精)。 您更靠近顶部的交换只是交换引用,下面的交换正好执行您期望引用执行的方式。

链接的文章引用参数…在Java中,所有参数都是按值,只是引用本身通过值传递,即REFERENCE(而不是其解除引用的内容)的更改不会反映在子例程的范围之外。

在java类中通常没有教授或遗漏数组的重要一点。 将数组传递给函数时,会为同一个数组创建另一个指针(永远不会传递相同的指针)。 您可以使用两个指针操作数组,但是一旦将第二个指针分配给被调用方法中的新数组并通过void返回调用函数,则原始指针仍保持不变。

您可以在此处直接运行代码: https : //www.compilejava.net/

 import java.util.Arrays; public class HelloWorld { public static void main(String[] args) { int Main_Array[] = {20,19,18,4,16,15,14,4,12,11,9}; Demo1.Demo1(Main_Array); // THE POINTER Main_Array IS NOT PASSED TO Demo1 // A DIFFERENT POINTER TO THE SAME LOCATION OF Main_Array IS PASSED TO Demo1 System.out.println("Main_Array = "+Arrays.toString(Main_Array)); // outputs : Main_Array = [20, 19, 18, 4, 16, 15, 14, 4, 12, 11, 9] // Since Main_Array points to the original location, // I cannot access the results of Demo1 , Demo2 when they are void. // I can use array clone method in Demo1 to get the required result, // but it would be faster if Demo1 returned the result to main } } public class Demo1 { public static void Demo1(int A[]) { int B[] = new int[A.length]; System.out.println("B = "+Arrays.toString(B)); // output : B = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] Demo2.Demo2(A,B); System.out.println("B = "+Arrays.toString(B)); // output : B = [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] System.out.println("A = "+Arrays.toString(A)); // output : A = [20, 19, 18, 4, 16, 15, 14, 4, 12, 11, 9] A = B; // A was pointing to location of Main_Array, now it points to location of B // Main_Array pointer still keeps pointing to the original location in void main System.out.println("A = "+Arrays.toString(A)); // output : A = [9999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // Hence to access this result from main, I have to return it to main } } public class Demo2 { public static void Demo2(int AAA[],int BBB[]) { BBB[0] = 9999; // BBB points to the same location as B in Demo1, so whatever I do // with BBB, I am manipulating the location. Since B points to the // same location, I can access the results from B } }