等价Java数组中的奇怪之处:引用与指针
在理解下面的代码时遇到问题。数组等价Java数组中的奇怪之处:引用与指针,java,arrays,pointers,Java,Arrays,Pointers,在理解下面的代码时遇到问题。数组c和d的行为是我所期望的。但是a和b发生了什么?(我也用普通变量和标量变量尝试了这一点,在这两种情况下都没有发生任何意外。) 输出被复制到右侧注释 import java.util.Arrays; public class ArraysParadox { public static void main(String[] args) { int[] c = {1, 2, 3}; int[] d = {6, 5, 4, 3
c
和d
的行为是我所期望的。但是a
和b
发生了什么?(我也用普通变量和标量变量尝试了这一点,在这两种情况下都没有发生任何意外。)
输出被复制到右侧注释
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]
}
}
结果是c
和d
返回时保持不变。如果Java(如C)将指向C
和d
的指针传递给方法,但它只是传递它们的值,而不改变原始变量,那么这将是可行的
将a=b
更改为a=b.clone()代码>或toa=Arrays.copyOf(b,b.length)代码>提供了我所期望的行为。此代码也适用于:
int[] tmp = new int[b.length];
System.arraycopy( b, 0, tmp, 0, b.length );
a = tmp;
描述了相对时间。数组初始值设定项在引擎盖下调用new(因此在本例中,它是语法糖精)。靠近顶部的交换只是交换引用,下面的交换正是您期望引用执行的方式
链接的文章提到了参数。。。在Java中,所有参数都是按值传递的,只是引用本身是按值传递的,即对引用的更改(不是其取消引用的内容)不会反映在子例程的范围之外。这里没有什么“奇怪”的事情:数组变量是对实际数组的引用(在其他语言中也称为指针)。当你操作数组变量时,你所做的就是操作指针
当您将一个数组变量分配给另一个数组变量时,您将为您分配的变量所指向的数组创建一个别名,并使之前被分配的变量所指向的数组符合垃圾收集的条件。因为分配a=b
使a
成为b
的别名,用数据的作用与用数据填充a
完全相同:一旦分配完成,a
和b
只是同一事物的两个不同名称
就传递值而言,在您的示例中没有一个是这样的:传递值的概念仅适用于将对象作为参数传递给您调用的方法。在您的示例中,变量a
、b
、c
和d
不是方法参数,它们是局部变量。您需要通过引用方法toString
和fill
(或者更准确地说,通过值将对对象的引用传递给toString
和fill
,因为在Java中,一切都是通过值传递的),这就是为什么从方法返回时,fill
对数组所做的修改是可见的。当您进行类似a=b;
的赋值时,如果a
和b
不是原语,则它们现在引用相同的对象。在您的情况下,它们现在引用相同的数组。您对eit所做的任何更改她的一个也会影响另一个(因为你只更新一个东西,而a
和b
都指向它)
请注意,此行为与Java中参数的传递方式无关。在Java类中,数组中有一个重要的点通常不会被教授或忽略。当数组传递给函数时,会创建另一个指向同一数组的指针(永远不会传递同一指针)。您可以使用这两个指针操作数组,但一旦将第二个指针指定给被调用方法中的新数组并通过void返回调用函数,则原始指针仍保持不变
您可以在此处直接运行代码:
请看我的回答:@Eng.Fouad,谢谢,这很有帮助。你能给我指一下setAttribute
的解释吗?嗨,杰夫,谢谢你的回答。所以当你说“数组初始值设定项正在调用引擎盖下的new”时,你说的是int[]tmp=c;
首先声明tmp
为一个全新的数组,然后将其等同于c
?即int[]tmp=newint[dims of c];tmp=c
。然而,这如何解释a
和b
的奇怪行为?你能扩展你的答案吗?“int[]a={blah};”实际上是在做“int[]a=new int[4]“然后在初始值设定项中添加项。因此,所有赋值都处于引用级别。很明显,Java完全是按值传递的,但您总是按值传递引用,而不是对象本身。(这与按值传递不同。)@LouisWasserman您是对的,“按值传递引用”的整个业务”很有可能会让事情变得混乱。谢谢你的提醒!@JohnK这种混乱是因为Java采用了单词reference来表示指针的意思。有一个微妙的区别:你可以说“对reference变量所做的任何操作都会直接改变原始变量”,你不能对指针说同样的话。它们增加了一个重要的限制——除了重新分配之外,操作会改变原始变量。换句话说,改变对象(例如,用新值填充数组)将通过两个变量显示,而重新分配其中一个变量将破坏别名。谢谢你,dasblinkenlight。我认为我的根本问题是不理解“引用”的含义。你所说的别名是有意义的。我链接的JavaDude文档这样说,“引用”是另一个变量的别名。因此,对引用变量所做的任何操作都会直接更改原始变量。”因此,它听起来像一个指针,但在计算机中不是物理地址(而且非常安全:无法指向沙盒外)。对吗?@JohnKfill
可以修改数组元素,因为它获取指向可变对象的指针。它可以
int[] tmp = new int[b.length];
System.arraycopy( b, 0, tmp, 0, b.length );
a = tmp;
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
}
}