Object.clone()默认实现浅拷贝:新建对象并逐字段复制,基本类型正常,引用类型仅复制地址,导致共享数据;必须实现Cloneable接口并重写clone()且调用super.clone(),对可变引用需手动深拷贝。

浅拷贝为什么只复制了引用,clone() 方法到底做了什么
Java 的 Object.clone() 默认实现是浅拷贝:它会新建一个对象,把原对象的字段值逐个复制过去。对基本类型没问题,但对引用类型(比如 ArrayList、自定义对象等),复制的是地址,不是新对象。结果就是两个对象共享同一份内部数据,改一个,另一个跟着变。
常见错误现象:Cloneable 接口没实现却调用 clone() → 抛 CloneNotSupportedException;实现了接口但没重写 clone() → 编译通过但运行时仍抛异常;重写了但没调用 super.clone() → 返回 null 或行为不可控。
- 必须显式实现
Cloneable接口(空接口,仅作标记) - 必须重写
public Object clone(),且第一行通常是super.clone() - 对每个可变引用字段,手动调用其
clone()或新建副本(如new ArrayList(this.items)) - 注意字段是否为
final:final引用无法在clone()中重新赋值,得在构造阶段处理
深拷贝用序列化最省事,但 Serializable 有硬性前提
把对象写成字节流再读回来,天然绕过引用共享问题,是公认的“无脑深拷贝”方案。但它要求整个对象图里所有非 transient 字段对应的类都实现 Serializable,缺一个就抛 NotSerializableException。
使用场景:对象结构稳定、不含不可序列化资源(如 Thread、Socket、Connection)、不追求极致性能。
- 必须确保目标类及所有嵌套引用类都声明
implements Serializable - 含
transient字段时,反序列化后该字段为默认值(null/0/false),需自行恢复 - 静态字段和方法不参与序列化,无需关心
- 避免在
readObject()中做耗时操作,否则每次深拷贝都拖慢性能
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(original); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); MyObj copy = (MyObj) ois.readObject();
第三方库(如 Apache Commons Lang)的 SerializationUtils.clone() 看似方便,其实只是封装了序列化
它底层还是走 ObjectInputStream/ObjectOutputStream,所以所有限制一个不少:类必须可序列化、不能有不可序列化字段、性能开销一样大。好处是少写样板代码,坏处是掩盖了底层约束,容易在上线后突然失败。
- 依赖引入后,
SerializationUtils.clone(obj)看起来一行解决,但异常堆栈依然指向NotSerializableException - 对含
lambda表达式或匿名内部类的对象,可能因生成类名不稳定而反序列化失败 - Android 环境默认禁用部分序列化机制,此方法大概率不可用
- 如果对象里有
java.time.*类型(Java 8+),需确认运行环境序列化支持是否完备(旧版 Android 可能出问题)
什么时候不该用深拷贝,以及替代思路
深拷贝本质是防御性复制,但很多场景根本不需要——比如对象本就是不可变的(String、LocalDateTime),或业务逻辑已保证单线程访问,或修改前本就会新建实例。强行深拷贝反而增加 GC 压力和 CPU 开销。
- 优先考虑设计不可变对象(
final字段 + 无 setter + 防御性返回副本) - 用构建器(Builder)模式替代拷贝,显式控制哪些字段要继承、哪些要重置
- 对集合字段,用
Collections.unmodifiableList()包装,比深拷贝更轻量且语义清晰 - 若只是临时避免并发修改,用
synchronized或CopyOnWriteArrayList更直接
真正麻烦的从来不是怎么拷贝,而是搞清“谁在什么时候会改这个对象”。不画清楚数据流向,光堆深拷贝只会把 bug 推迟暴露而已。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











