java中clone方法默认只实现浅拷贝,深拷贝需手动递归实现:所有引用类型必须实现cloneable并重写clone(),集合等容器需遍历克隆元素,基本类型和不可变对象直接复制,循环引用需缓存避免栈溢出。

Java 中 clone 方法本身不提供深拷贝,必须通过手动递归策略实现。核心在于:对每个可变引用字段,不是直接复制引用,而是调用其自身的 clone() 方法(或等价的副本构造逻辑),逐层向下展开,直到所有嵌套对象都生成独立副本。
递归克隆的关键前提
要让递归生效,整个对象图中的每一层引用类型都必须支持克隆:
- 所有参与克隆的类都要实现
Cloneable接口 - 每个类都需重写
public的clone()方法,并确保它返回本类实例(协变返回) - 不可变类型(如
String、Integer)无需递归,直接赋值即可 - 集合类(如
ArrayList)默认是浅拷贝,若其中存的是可变对象,需遍历并克隆每个元素
如何处理嵌套集合字段
当对象包含 List<address></address> 这类字段时,不能只克隆列表容器,还要克隆每个 Address 元素:
- 先调用
list.clone()得到新列表(仍是浅拷贝,元素引用未变) - 再遍历原列表,对每个
address调用address.clone(),并将结果加入新列表 - 避免直接用
new ArrayList(originalList),这只会复制引用,不是深拷贝
递归终止条件与边界控制
递归不会无限进行,靠 Java 类型系统自然收敛:
- 基本类型和不可变对象(
String、LocalDate等)直接复制,不再深入 - 空引用(
null)跳过克隆,直接赋值null - 循环引用需额外处理(如用 Map 缓存已克隆对象),否则会栈溢出;标准
clone()不自动处理该情况 - 如果某字段类型未实现
Cloneable或未重写clone(),运行时抛CloneNotSupportedException
为什么不能依赖 super.clone() 一步到位
super.clone() 只完成本层字段的浅拷贝:
- 它复制的是字段值——对引用类型,就是内存地址,不是对象内容
- 它不知道你的业务逻辑,无法判断哪些字段需要深拷贝、哪些可以共享
- 它不检查子对象是否可克隆,也不帮你遍历集合或处理数组
- 所以必须在重写的
clone()方法中,显式接管每个引用字段的复制逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











