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

Man*_*uel 2 java arrays object

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();
}
}
Run Code Online (Sandbox Code Playgroud)

如您所见,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];
    }
Run Code Online (Sandbox Code Playgroud)

对此

    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);
    }
Run Code Online (Sandbox Code Playgroud)

输出从此变化

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
Run Code Online (Sandbox Code Playgroud)

对此

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
Run Code Online (Sandbox Code Playgroud)

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

T.J*_*der 9

但是如果我在第一个for循环的末尾删除行"t = new int [5]"(即,如果我没有"重置"t),那么我的Cs数组中的每个对象都会打印出来最后分配的5个数字.

这是因为通过不创建新数组,您将使所有条目都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();
    }
}
Run Code Online (Sandbox Code Playgroud)

为了说明创建新阵列和不创建新阵列时会发生什么,让我们为内存中的内容做一些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];
}
Run Code Online (Sandbox Code Playgroud)

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

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

注意这些值tc,我已经证明那里Ref5462Ref2634分别.这些是对象参考.它们是值(就像int一个值),它们告诉Java运行时它们引用的数组在内存中的其他位置.即,该阵列是未该变量,该位置阵列的是在变量.(我们从未看到实际值,我在这里使用的数字只是概念性的.)

然后我们运行j循环并填入以下值t:

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

然后我们存储的值的副本tc[0]:

[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];
}
Run Code Online (Sandbox Code Playgroud)

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

[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    |
                                  +?????????+

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