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]”行? 解决方法
这是因为通过不创建新数组,您将使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 | +?????????+ 所以很自然地,当你输出它时,你会看到重复相同的值. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |