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]”行?
答案 0 :(得分: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();
}
}
为了说明在创建新数组和不创建新数组时发生了什么,让我们为内存中的内容做一些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运行时它们引用的数组在内存中别处。也就是说,数组不是 in 变量,数组的 location 在变量中。 (我们从未看到实际值,我在这里使用的数字只是概念性的。)
然后我们运行j
循环并在t
中填写值:
[t:Ref5462]−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−+ | [c:Ref2534]−−>| (array) | | +−−−−−−−−−−−−+ \ +−−−−−−−−−+ | 0: null | +−>| (array) | | 1: null | +−−−−−−−−−+ | 2: null | | 0: 9 | +−−−−−−−−−−−−+ | 1: 6 | | 2: 5 | +−−−−−−−−−+
然后我们会在t
中存储c[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
之间没有关联,它们只有相同的值。
然后我们创建一个 new 数组,并在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]
仍然指向旧的。
现在我们再次循环并填写 new 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 | +−−−−−−−−−+
很自然地,当你输出它时,你会看到重复的相同值。
答案 1 :(得分:2)
如果您在致电System.out.println(java.util.Arrays.toString(t));
后添加c[i] = new C(t);
,我认为您可以看到自己做错了什么。问题是您将C的新实例的引用作为参数。如果您稍后更改了数组的内容,还会更改&#34; old&#34;的内容。 C的实例,因为它们使用相同的t实例。如果您不想制作新数组,可以复制数组:c[i] = new C(java.util.Arrays.copyOf(t, t.length));
然后您可以删除第t = new int[5];
行
答案 2 :(得分:1)
发生的事情非常简单。每次你做
t = new int[5]
你指向一个新的参考。当你不写这一行时,你只是替换你的t元素,而不是它的引用,所以你的所有C对象都指向同一个t数组。在循环结束时,您只需使用最后5个随机数的数组t以及指向它的所有5个C对象。如果不想放置该行,您可以做的是复制C构造函数中的值,而不是仅将数据POINT输入。有更好的方法,但你可以这样做,作为一个快速解决方案,以了解&#34; =&#34;操作者:
private class C {
int[] data;;
C(int[] input) {
data = new int[data.length];
for(int i = 0; i < data.length; i++){
data[i] = input[i];
}
}
void print() {
for (int i = 0; i < data.length; i++)
System.out.print(data[i] + " ");
System.out.println();
}
}
现在您在每个C中都有一个新数组,因此当您在循环内为t分配新值时,它不会受到影响。
答案 3 :(得分:1)
由于我认为其他解释是好的,而不是试图再向你解释,我会告诉你这是一个小例子,应该有助于你理解。您应该能够将其复制粘贴到main
并运行它。然后尝试搞清楚:
Random r = new Random();
int[] t = new int[5];
for (int j=0; j<5; j++)
t[j] = r.nextInt(10) + 1;
C c = new C(t);
c.print(); // 7 3 8 10 6 //ok everything clear so far
// now let's change the content of t - not touching c!
for (int j=0; j<5; j++)
t[j] = r.nextInt(10) + 1;
c.print(); // 8 9 2 4 5 //huh? content changed... hmm
C c2 = new C(t);
c2.print(); // 8 9 2 4 5 //right...the same thing
for (int j=0; j<5; j++)
t[j] = r.nextInt(10) + 1;
c.print(); // 10 8 8 4 7 // yeah, kind of expecting this
c2.print(); // 10 8 8 4 7 // but I still don't get why exactly
//ok let's make a new t
t = new int[5];
for (int j=0; j<5; j++)
t[j] = r.nextInt(10) + 1;
c.print(); // 10 8 8 4 7 // oh!
c2.print(); // 10 8 8 4 7 //now changing t doesn't influence the C's anymore
C c3 = new C(t);
c3.print(); // 3 10 7 9 4 // ah, here is the new t..
for (int j=0; j<5; j++)
t[j] = r.nextInt(10) + 1;
c.print(); // 10 8 8 4 7 // still the old stuff
c2.print(); // 10 8 8 4 7 // yeah, also still the old stuff
c3.print(); // 9 1 1 1 5 // aha! right!
//let's check if I understood it:
t = new int[5];
for (int j=0; j<5; j++)
t[j] = r.nextInt(10) + 1;
c3.print(); // 9 1 1 1 5 // ok, I think I got it!