如何不借助Cloneable/arraycopy及显式类型转换,用拷贝构造函数深拷贝对象数组?
问题解答
核心结论
- 可以调用对象的拷贝构造函数,但不能用你当前这种父类构造硬转的方式,得靠多态让子类自己暴露拷贝能力。
- 现有代码必须修改,当前写法本质是把所有子类对象降级成父类实例拷贝,完全丢失子类属性和行为,且硬转+异常捕获的方式既丑陋又不可扩展。
- 多态完全支持这个场景,通过父类定义抽象拷贝接口,子类实现具体逻辑,就能在运行时自动匹配对应子类的拷贝行为,无需显式类型转换。
具体修改方案
1. 重构父类Building,定义抽象拷贝方法
把Building改成抽象类,新增一个copy()抽象方法,强制所有子类实现自己的拷贝逻辑:
public abstract class Building { protected int windows; protected boolean basement; // 供子类调用的基础构造 protected Building(int windows, boolean basement) { this.windows = windows; this.basement = basement; } // 抽象拷贝方法,子类需实现 public abstract Building copy(); }
2. 子类实现拷贝构造和copy()方法
每个子类编写自己的拷贝构造函数,并在copy()方法中调用该构造返回子类实例:
以House为例:
public class House extends Building { private boolean hasGarage; // 子类特有属性 // 普通构造 public House(int windows, boolean basement, boolean hasGarage) { super(windows, basement); this.hasGarage = hasGarage; } // 子类拷贝构造函数 public House(House other) { super(other.windows, other.basement); this.hasGarage = other.hasGarage; } // 实现父类拷贝方法 @Override public Building copy() { return new House(this); } }
另一个子类Apartment同理:
public class Apartment extends Building { private int floor; // 子类特有属性 public Apartment(int windows, boolean basement, int floor) { super(windows, basement); this.floor = floor; } public Apartment(Apartment other) { super(other.windows, other.basement); this.floor = other.floor; } @Override public Building copy() { return new Apartment(this); } }
3. 修改数组拷贝方法
直接调用每个对象的copy()方法,依赖多态自动触发对应子类的拷贝逻辑:
public static Building[] copyBuildings(Building[] objects) { Building[] objList = new Building[objects.length]; for (int i = 0; i < objects.length; i++) { objList[i] = objects[i].copy(); } return objList; }
方案优势
- 完全规避显式类型转换:子类自己处理拷贝逻辑,父类只提供统一接口。
- 多态生效:运行时JVM会根据对象实际类型调用对应的
copy()方法,返回正确的子类实例,不会丢失子类属性。 - 可扩展性强:新增子类时,只需要实现拷贝构造和
copy()方法即可,无需修改父类或数组拷贝逻辑。
原代码问题分析
你原来的Building(Object obj)构造函数通过捕获ClassCastException来适配不同子类,这种方式存在致命问题:
- 所有拷贝出的对象都是
Building类型,子类特有的属性会丢失。 - 新增子类时,必须在父类构造中新增对应的try-catch块,违反开闭原则。
- 代码可读性差,硬转的逻辑容易出错。
内容的提问来源于stack exchange,提问作者Gray
相关产品推荐
相关产品推荐

