如何实现嵌套ArrayList的克隆?Java开发技术问询
克隆嵌套
ArrayList<ArrayList<Ship>>的正确方式 嘿,我懂你的问题所在——你当前的代码只是把原列表里的子ArrayList的引用直接加到了seaClone里,这属于浅拷贝。也就是说,theSea里的子列表和seaClone里的子列表其实是同一个对象,修改其中一个的元素(比如新增、删除Ship),另一个也会跟着变;而且如果Ship对象本身的属性被修改,原列表和克隆列表里的Ship都会受到影响,因为它们指向的是同一个实例。
下面分两种常见需求给你解决方案:
需求1:仅克隆嵌套的ArrayList结构,Ship对象保持原引用
如果你只需要让seaClone的列表结构独立于原列表(比如可以单独增删子列表里的Ship元素,但Ship的属性修改会同步),可以给每个子列表创建新的ArrayList实例,复制原有的Ship引用:
ArrayList<ArrayList<Ship>> seaClone = new ArrayList<>(); for (ArrayList<Ship> row : theSea) { // 新建ArrayList并传入原row,快速复制所有Ship引用 seaClone.add(new ArrayList<>(row)); }
这种方式简单高效,适合不需要完全隔离Ship对象的场景。
需求2:完全深拷贝,连Ship对象也独立克隆
如果你需要让seaClone里的所有Ship对象都和原列表完全独立(修改克隆后的Ship属性不会影响原列表),那需要Ship类本身支持克隆,常见的实现方式有两种:
方式A:给Ship实现拷贝构造函数
先给Ship类添加一个拷贝构造函数,用来复制原Ship的所有属性:
public class Ship { // 假设Ship的属性示例 private int positionX; private int positionY; private String shipName; // 拷贝构造函数 public Ship(Ship originalShip) { this.positionX = originalShip.positionX; this.positionY = originalShip.positionY; this.shipName = originalShip.shipName; // 如果有其他引用类型属性(比如武器、船员列表),也要手动复制其克隆对象 } // 其他业务方法... }
然后遍历嵌套列表,逐个克隆Ship并添加到新的子列表中:
ArrayList<ArrayList<Ship>> seaClone = new ArrayList<>(); for (ArrayList<Ship> row : theSea) { ArrayList<Ship> clonedRow = new ArrayList<>(); for (Ship ship : row) { // 通过拷贝构造函数创建独立的Ship实例 clonedRow.add(new Ship(ship)); } seaClone.add(clonedRow); }
方式B:让Ship实现Cloneable接口
另一种方式是让Ship实现Cloneable接口并重写clone方法:
public class Ship implements Cloneable { private int positionX; private int positionY; private String shipName; @Override protected Ship clone() throws CloneNotSupportedException { // 先调用父类的clone方法完成基本类型属性的复制 Ship clonedShip = (Ship) super.clone(); // 如果有引用类型属性,比如List<Crew>,需要在这里手动克隆: // clonedShip.setCrew(new ArrayList<>(this.getCrew())); return clonedShip; } // 其他业务方法... }
然后在克隆列表时调用ship.clone():
ArrayList<ArrayList<Ship>> seaClone = new ArrayList<>(); try { for (ArrayList<Ship> row : theSea) { ArrayList<Ship> clonedRow = new ArrayList<>(); for (Ship ship : row) { clonedRow.add(ship.clone()); } seaClone.add(clonedRow); } } catch (CloneNotSupportedException e) { // 处理克隆异常,比如转为运行时异常抛出 e.printStackTrace(); throw new RuntimeException("Failed to clone Ship instance", e); }
注意事项
如果Ship类包含其他引用类型的属性(比如另一个自定义对象、集合),那么在克隆Ship时,也要对这些属性进行深拷贝,否则这些属性还是会和原Ship共享引用,达不到完全独立的效果。
内容的提问来源于stack exchange,提问作者 Brian
相关产品推荐
相关产品推荐

