原型模式中实现深拷贝需确保对象及其所有嵌套引用类型完全独立:手动克隆需实现cloneable、重写clone()并递归复制引用字段;序列化方式要求所有类实现serializable,推荐用serializationutils.clone();须规避final字段、第三方类不可克隆、循环引用等陷阱,并通过修改测试验证独立性。

原型模式中实现深拷贝,核心是让克隆出的对象及其所有嵌套引用类型成员都完全独立,不共享任何内存地址。浅拷贝只复制一层对象,引用字段仍指向原对象;深拷贝则递归复制整个对象图,切断所有引用链。
手动重写 clone() 并逐层克隆引用字段
这是最直接可控的方式,适用于结构明确、嵌套层级不深的类。关键点是:对每个引用类型字段,不能直接赋值,而要调用其自身的 clone() 方法(前提是它也支持克隆)或新建实例并复制内容。
- 类必须实现 Cloneable 接口,否则调用 super.clone() 会抛出 CloneNotSupportedException
- 重写 clone() 方法时,先调用 super.clone() 获取浅拷贝对象
- 对每个引用类型字段(如 List、自定义对象等),单独创建新实例并复制内容,例如:
copy.address = new Address(original.address.city); - 若引用类型本身也含引用字段,需确保它也实现了深拷贝逻辑,否则链路断裂
利用序列化实现通用深拷贝
借助 Java 的序列化机制,将对象写入字节流再反序列化还原,天然绕过引用共享问题。只要对象及其所有字段都实现了 Serializable 接口,就能获得真正的深拷贝。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 推荐使用 Apache Commons Lang 的 SerializationUtils.clone(),一行代码完成
- 自行实现时需注意:捕获 IOException 和 ClassNotFoundException,且不能传入 null
- transient 字段会被跳过,反序列化后为默认值(null/0),如有业务含义需额外处理
- 性能略低于手动克隆,但代码简洁、不易出错,适合复杂嵌套结构
避免常见陷阱
深拷贝不是“写了 clone 就万事大吉”,几个典型坑点必须警惕:
- 忽略 final 字段:final 引用类型在 clone 中无法重新赋值,需在构造时就设计为可复制,或改用非 final + 显式初始化
- 第三方类未实现 Serializable 或 Cloneable:比如某些工具类、外部 SDK 对象,需包装或提供自定义拷贝逻辑
- 循环引用:对象 A 引用 B,B 又引用 A,序列化可能栈溢出,手动克隆需加 visited 集合判重
- clone() 方法未声明为 public:Object.clone() 是 protected,子类重写后建议改为 public,便于外部调用
验证是否真正深拷贝
写个简单测试比看文档更可靠:修改克隆对象的某个引用字段(如 list.add()、address.setCity()),然后检查原对象对应字段是否 unchanged。只要有一处被联动修改,说明还有浅拷贝残留。
- 重点测嵌套两层以上的引用,例如 Person → Address → ZipCode
- 集合类(ArrayList、HashMap)最容易被忽略,它们本身是引用类型,add 元素不影响原集合,但若元素是自定义对象,仍需确保元素也被深拷贝
- 字符串、Integer 等不可变类型无需深拷贝,复制引用也安全,不必过度处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










