Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
等价Java数组中的奇怪之处:引用与指针_Java_Arrays_Pointers - Fatal编程技术网

等价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()或to
a=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文档这样说,“引用”是另一个变量的别名。因此,对引用变量所做的任何操作都会直接更改原始变量。”因此,它听起来像一个指针,但在计算机中不是物理地址(而且非常安全:无法指向沙盒外)。对吗?@JohnK
fill
可以修改数组元素,因为它获取指向可变对象的指针。它可以
    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
    }
}