Java二维数组克隆后内容异常变更问题求助
问题:二维数组克隆后内容在循环结束后异常变更
我写了一个通过试错生成最优数组的方法:在if (rating < bestRating)判断里打印克隆得到的bestRation数组时,能看到逐步优化的有效数据;但while循环结束后再读取这个数组,第二维度的内容全变成了0。为什么数组内容会在判断之外发生变更?
相关代码与测试情况
数组定义
private double[][] ration //ration[0].length 始终为2
方法起始代码
private void suggestRation() { // 计时器 Stopwatch suggestionWatch = new Stopwatch(); suggestionWatch.startO(); // 获取评分基准 int mode = loadUserRation(); double[][] bestRation = ration.clone(); double bestRating = submit(); // 最大组件数量 int max = MainClass.getRation().getComponentList().getSize(); int lines = MainClass.getRation().getRationGrid().length(true); if (max > lines) { max = lines; } int loops = 0; long lapseEnd = System.nanoTime() + (long) (duration * 1.0E9); long lapseMin = System.nanoTime() + (long) (duration * 1.0E8);
核心逻辑与异常代码
while (System.nanoTime() < lapseEnd) { switch (mode) { case NEW: int components = (new Random()).nextInt(max); generateNewRation(components); break; case REFINE: generateNewAmounts(); break; case EXTEND: expandRation(); break; } double rating = submit(); if (rating < bestRating) { bestRation = ration.clone(); bestRating = rating; // 这里能正确打印出优化后的数组 for (int i = 0; i < bestRation.length; i++) { System.out.println(bestRation[i][0] + " " +bestRation[i][1]); } } loops++; if (bestRating < 5 && System.nanoTime() > lapseMin) { break; } } // 这里打印时第二列全为0,和上面最后一次输出不一致 for (int i = 0; i < bestRation.length; i++) { System.out.println(bestRation[i][0] + " " + bestRation[i][1]); } ration = bestRation.clone();
触发的分支代码(REFINE模式)
private void generateNewAmounts() { double max_amount = Constants.FM_MAX; for (int i = 0; i < ration.length; i++) { if (ration[i][0] != -1) { ration[i][1] = (new Random().nextInt((int) (max_amount - 1)) + 1); } } }
测试输出情况
- 循环内的打印输出(每次找到更优解时):
0.0 37.0 0.0 51.0 0.0 50.0 0.0 44.0 0.0 45.0
- 循环结束后的打印输出:
0.0 0.0
- 预期输出:
0.0 45.0
原因与解决方案
问题根源:二维数组的浅克隆
Java中double[][]的clone()方法是浅克隆:它只会复制外层数组的引用,不会复制内层的一维数组。也就是说,bestRation = ration.clone()执行后,bestRation和ration的外层数组是不同对象,但它们的每个元素(一维数组)都指向同一个内存地址。
后续循环中调用generateNewAmounts()修改ration[i][1]时,实际上直接修改了bestRation内部引用的一维数组内容——因为二者共享内层数组。循环内打印时,是在修改前输出当前值;但循环结束前的最后几次循环可能没触发if (rating < bestRating)的更新,此时ration的内容被修改成0,bestRation还指向旧的内层数组,最终打印出的就是被后续修改后的值。
解决方案:实现深克隆
要真正复制二维数组的所有内容,需要手动实现深克隆,有两种常用方式:
方式1:手动遍历复制每个元素
替换bestRation = ration.clone()为以下代码:
bestRation = new double[ration.length][2]; for (int i = 0; i < ration.length; i++) { bestRation[i][0] = ration[i][0]; bestRation[i][1] = ration[i][1]; }
方式2:使用Arrays.copyOf复制内层数组
也可以用Arrays.copyOf复制每个一维数组:
bestRation = new double[ration.length][]; for (int i = 0; i < ration.length; i++) { bestRation[i] = Arrays.copyOf(ration[i], ration[i].length); }
修改后,bestRation会拥有完全独立的内存空间,后续修改ration不会影响到它,循环结束后就能保留最后一次更新的最优数组内容。
内容的提问来源于stack exchange,提问作者hinrich.
相关产品推荐
相关产品推荐

