java – 为什么我的数组中的最后一个元素会覆盖以前的所有元素?

参见英文答案 > Why does my ArrayList contain N copies of the last item added to the list?                                    4个

import java.util.Random;

public class B {
private class C {
    int[] data = new int[5];
    C (int[] input) {data = input;}

    void print() {
        for (int i=0; i<5; i++)
            System.out.print(data[i] + " " );
        System.out.println();
    }
}

C[] c;

B () {
    Random r = new Random();
    c = new C[5];
    int[] t = new int[5];

    for (int i=0; i<5; i++) {
        for (int j=0; j<5; j++)
            t[j] = r.nextInt(10) + 1;
        c[i] = new C(t);
        t = new int[5];
    }

    for (int k=0; k<5; k++)
        c[k].print();
}

public static void main(String[] args) {
    B b = new B();
}
}

如您所见,C类是B的内部类.在B中,我有一个C类型的对象数组,恰当地称为“c”.在C中,我有一个接受整数数组的构造函数.

我在这里做的是对于C数组中的每个元素,我正在生成一个包含5个整数的随机列表,并将其传递给相应C对象的构造函数.

此代码按预期工作; Cs数组中的每个对象都有一个不同的随机整数数组.但是如果我在第一个for循环的末尾删除行“t = new int [5]”(即,如果我没有“重置”t),那么我的Cs数组中的每个对象都会打印出来最后分配的5个数字.

换句话说,如果我改变这一点

    for (int i=0; i<5; i++) {
        for (int j=0; j<5; j++)
            t[j] = r.nextInt(10) + 1;
        c[i] = new C(t);
        t = new int[5];
    }

对此

    for (int i=0; i<5; i++) {
        for (int j=0; j<5; j++)
            t[j] = r.nextInt(10) + 1;
        c[i] = new C(t);
    }

输出从此变化

9 6 5 3 7
2 7 7 3 9
4 5 8 3 9
9 8 3 5 8
4 8 5 5 4

对此

7 1 5 8 9
7 1 5 8 9
7 1 5 8 9
7 1 5 8 9
7 1 5 8 9

为什么会这样?不应该每个新的C对象都得到一组新的输入,因为在每次循环之后,t的内容都会改变,无论是否存在“t = new int [5]”行?

最佳答案

But if I remove the line “t = new int[5]” at the end of the first for-loop (ie., if I don’t “reset” t), then every object in my array of Cs prints the same 5 numbers that were the last to be assigned.

这是因为通过不创建新数组,您将使c中的所有条目都引用相同的数组.所以你自然会看到数组的相同内容.

我建议,因为t仅对特定循环迭代有用,所以在循环中声明并创建它.请记住:变量的范围应尽可能窄.所以:

B () {
    Random r = new Random();
    c = new C[5];
    // Don't declare or initialize it here: int[] t;  = new int[5];

    for (int i=0; i<5; i++) {
        int t[] = new int[5];           // *** Keep it specific to the loop, and
                                        //     create a new one each iteration
        for (int j=0; j<5; j++) {
            t[j] = r.nextInt(10) + 1;
        }
        c[i] = new C(t);
    }

    for (int k=0; k<5; k++) {
        c[k].print();
    }
}

为了说明创建新阵列和不创建新阵列时会发生什么,让我们为内存中的内容做一些ASCII艺术,但是使用3个元素而不是5个来保持图片更小:

每次使用该行创建一个新数组:

Random r = new Random();
c = new int[3];
int[] t = new int[3];
for (int i = 0; i < c.length; ++i) {
    for (int j = 0; j < t.length; ++j0 {
        t[j] = r.nextInt(10) + 1;
    }
    c[i] = t;
    t = new int[3];
}

在循环之前,我们在内存中有这个:

[t:Ref5462]−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+  |
[c:Ref2534]−−>| (array)    |  |
              +−−−−−−−−−−−−+  \   +−−−−−−−−−+
              | 0: null    |   +−>| (array) |
              | 1: null    |      +−−−−−−−−−+
              | 2: null    |      | 0: 0    |
              +−−−−−−−−−−−−+      | 1: 0    |
                                  | 2: 0    |
                                  +−−−−−−−−−+

注意t和c中的那些值,我在那里分别显示为Ref5462和Ref2634.这些是对象参考.它们是值(就像int是一个值),它们告诉Java运行时它们引用的数组在内存中的其他位置.也就是说,数组不在变量中,数组的位置在变量中. (我们从未看到实际值,我在这里使用的数字只是概念性的.)

然后我们运行j循环并在t中填入值:

[t:Ref5462]−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+  |
[c:Ref2534]−−>| (array)    |  |
              +−−−−−−−−−−−−+  \   +−−−−−−−−−+
              | 0: null    |   +−>| (array) |
              | 1: null    |      +−−−−−−−−−+
              | 2: null    |      | 0: 9    |
              +−−−−−−−−−−−−+      | 1: 6    |
                                  | 2: 5    |
                                  +−−−−−−−−−+

然后我们在c [0]中存储t值的副本:

[t:Ref5462]−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+  |
[c:Ref2534]−−>| (array)    |  |
              +−−−−−−−−−−−−+  \   +−−−−−−−−−+
              | 0: Ref5462 |−−−+−>| (array) |
              | 1: null    |      +−−−−−−−−−+
              | 2: null    |      | 0: 9    |
              +−−−−−−−−−−−−+      | 1: 6    |
                                  | 2: 5    |
                                  +−−−−−−−−−+

注意c [0]和t现在如何包含相同的值.它们都引用相同的数组. c [0]和t之间没有链接,它们只有相同的值.

然后我们创建一个新数组并在t中存储对它的新引用:

[t:Ref8465]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+                  |
[c:Ref2534]−−>| (array)    |                  |
              +−−−−−−−−−−−−+      +−−−−−−−−−+ |
              | 0: Ref5462 |−−−−−>| (array) | |
              | 1: null    |      +−−−−−−−−−+ |
              | 2: null    |      | 0: 9    | |
              +−−−−−−−−−−−−+      | 1: 6    | |
                                  | 2: 5    | |
                                  +−−−−−−−−−+ |  +−−−−−−−−−+
                                              +−>| (array) |
                                                 +−−−−−−−−−+
                                                 | 0: 0    |
                                                 | 1: 0    |
                                                 | 2: 0    |
                                                 +−−−−−−−−−+

注意t中有一个新引用,它指向新数组. c [0]仍然指向旧的.

现在我们再次循环并填入新的t,然后将新t的值存储在c [1]中:

[t:Ref8465]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+                  |
[c:Ref2534]−−>| (array)    |                  |
              +−−−−−−−−−−−−+      +−−−−−−−−−+ |
              | 0: Ref5462 |−−−−−>| (array) | |
              | 1: Ref8465 |−−−+  +−−−−−−−−−+ |
              | 2: null    |   |  | 0: 9    | |
              +−−−−−−−−−−−−+   |  | 1: 6    | |
                               |  | 2: 5    | |
                               |  +−−−−−−−−−+ \   +−−−−−−−−−+
                               +−−−−−−−−−−−−−−−+−>| (array) |
                                                  +−−−−−−−−−+
                                                  | 0: 2    |
                                                  | 1: 7    |
                                                  | 2: 7    |
                                                  +−−−−−−−−−+

注意c [0]和c [1]如何引用不同的数组.

然后我们再次完成所有操作,创建另一个数组,并以此结束:

[t:Ref3526]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+                                 |
[c:Ref2534]−−>| (array)    |                                 |
              +−−−−−−−−−−−−+      +−−−−−−−−−+                |
              | 0: Ref5462 |−−−−−>| (array) |                |
              | 1: Ref8465 |−−−+  +−−−−−−−−−+                |
              | 2: Ref3526 |−+ |  | 0: 9    |                |
              +−−−−−−−−−−−−+ | |  | 1: 6    |                |
                             | |  | 2: 5    |                |
                             | |  +−−−−−−−−−+    +−−−−−−−−−+ |
                             | +−−−−−−−−−−−−−−−−>| (array) | |
                             |                   +−−−−−−−−−+ |
                             |                   | 0: 2    | |
                             |                   | 1: 7    | |
                             |                   | 2: 7    | |
                             |                   +−−−−−−−−−+ \   +−−−−−−−−−+
                             +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| (array) |
                                                                 +−−−−−−−−−+
                                                                 | 0: 4    |
                                                                 | 1: 5    |
                                                                 | 2: 8    |
                                                                 +−−−−−−−−−+

现在,让我们来看看,如果你不是每次都创建一个新的t:

Random r = new Random();
c = new int[3];
int[] t = new int[3];
for (int i = 0; i < c.length; ++i) {
    for (int j = 0; j < t.length; ++j0 {
        t[j] = r.nextInt(10) + 1;
    }
    c[i] = t;
    // What if we leave this out? t = new int[3];
}

起初,事情似乎是一样的.在这里,我们再次进行第一次循环:

[t:Ref5462]−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+  |
[c:Ref2534]−−>| (array)    |  |
              +−−−−−−−−−−−−+  \   +−−−−−−−−−+
              | 0: Ref5462 |−−−+−>| (array) |
              | 1: null    |      +−−−−−−−−−+
              | 2: null    |      | 0: 9    |
              +−−−−−−−−−−−−+      | 1: 6    |
                                  | 2: 5    |
                                  +−−−−−−−−−+

但在这一点上,我们不会创建一个新的数组.所以在第二个循环之后,t引用的前一个数组中有新值,我们在c [1]中存储了它的位置副本:

[t:Ref5462]−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+  |
[c:Ref2534]−−>| (array)    |  |
              +−−−−−−−−−−−−+  \   +−−−−−−−−−+
              | 0: Ref5462 |−−−+−>| (array) |
              | 1: Ref5462 |−−/   +−−−−−−−−−+
              | 2: null    |      | 0: 2    |
              +−−−−−−−−−−−−+      | 1: 7    |
                                  | 2: 7    |
                                  +−−−−−−−−−+

现在,t,c [0]和c [1]都指向相同的数组.在下一个循环之后,我们再次更新了该数组的内容,并指出了c [2]:

[t:Ref5462]−−−−−−−−−−−−−−−−−−−+
              +−−−−−−−−−−−−+  |
[c:Ref2534]−−>| (array)    |  |
              +−−−−−−−−−−−−+  \   +−−−−−−−−−+
              | 0: Ref5462 |−−−+−>| (array) |
              | 1: Ref5462 |−−/   +−−−−−−−−−+
              | 2: Ref5462 |−/    | 0: 7    |
              +−−−−−−−−−−−−+      | 1: 1    |
                                  | 2: 5    |
                                  +−−−−−−−−−+

所以很自然地,当你输出它时,你会看到重复相同的值.

转载注明原文:java – 为什么我的数组中的最后一个元素会覆盖以前的所有元素? - 代码日志