Java修改数组时如何避免已存入Deque的历史数据同步变更
问题根因
你之前试的数组拷贝方法是浅拷贝,根本没切断引用关联:
Arrays.stream(cells).toArray(Cell[][]::new)只创建了新的外层二维数组对象,内层存的每一行Cell[]数组还是原数组的引用- 核心问题是数组里存的
Cell是可变对象,浅拷贝不会复制Cell实例本身,快照和原数组指向同一个Cell对象,你改原对象的值,所有引用这个对象的地方都会同步变。
你之前用的List拷贝方案其实也是浅拷贝,只有当List存的是不可变对象(比如基础类型包装类、String)时才不会出问题,如果List存的是自定义可变对象,一样要做深拷贝才能避免联动修改。
解决方案
存快照的时候做完整深拷贝,保证队列里存的二维数组、内层行数组、每个Cell实例全是独立的新对象,和原数据完全没有引用关联。
循环实现(可读性最好,性能最优)
// 生成当前棋盘状态的深拷贝快照 Cell[][] snapshot = new Cell[cells.length][]; for (int i = 0; i < cells.length; i++) { snapshot[i] = new Cell[cells[i].length]; for (int j = 0; j < cells[i].length; j++) { Cell source = cells[i][j]; if (source != null) { // 创建全新Cell实例,复制属性值 snapshot[i][j] = new Cell(source.getValue()); } } } // 只把独立快照存入队列 cellsReserved.add(snapshot);
流式实现(代码更简洁)
Cell[][] snapshot = Arrays.stream(cells) .map(row -> Arrays.stream(row) .map(cell -> cell == null ? null : new Cell(cell.getValue())) .toArray(Cell[]::new)) .toArray(Cell[][]::new); cellsReserved.add(snapshot);
替换后运行结果就符合预期,会依次输出5、10。
注意:如果后续
Cell类新增其他可变成员字段,拷贝逻辑里必须同步复制这些字段的内容,不然还是会有引用共享的问题。
内容的提问来源于stack exchange,提问作者Ensei
相关产品推荐
相关产品推荐

