浅拷贝只复制对象本身和基本类型字段,引用类型字段仍指向原对象;深拷贝则递归复制所有层级的对象,新对象与原对象完全独立。

Java 中的浅拷贝和深拷贝,核心区别在于是否复制对象内部引用类型所指向的数据。浅拷贝只复制对象本身和基本类型字段,引用类型字段仍指向原对象;深拷贝则递归复制所有层级的对象,新对象与原对象完全独立。
浅拷贝:用 clone() + 实现 Cloneable 接口
Java 原生支持浅拷贝,前提是类实现 Cloneable 接口并重写 clone() 方法。注意:Cloneable 是个标记接口,不提供方法,但不实现会抛 CloneNotSupportedException。
示例:
public class Person implements Cloneable {
private String name;
private Address address; // 引用类型
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 默认是浅拷贝
}
}
调用后:name 字段被复制(String 不可变,效果类似深拷贝),但 address 引用仍指向原对象。修改新对象的 address.city,原对象也会变。
深拷贝:手动克隆引用字段或用序列化
要真正隔离对象图,必须让每个引用字段也生成新实例。常见方式有:
- 在 clone() 中手动 new 并复制引用字段:适合结构简单、字段可控的类。例如对 address 字段调用 address.clone()(需 Address 也支持克隆)
- 借助序列化(推荐用于复杂嵌套对象):将对象写入字节数组再反序列化,天然实现深拷贝。要求所有字段类型都实现 Serializable
序列化方式示例:
public static <t extends serializable> T deepCopy(T obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
@SuppressWarnings("unchecked")
T copy = (T) ois.readObject();
ois.close();
return copy;
}
</t>
注意点:不可变类、集合、第三方库
String、LocalDateTime 等不可变类,即使浅拷贝也安全;但 ArrayList、HashMap 等容器类需特别处理——它们自身被复制了,但其中元素仍是原引用。
建议:
- 若使用频繁,可封装工具方法或用 Lombok 的
@Builder(toBuilder = true)构建新实例 - Gson / Jackson 可将对象转 JSON 再解析(适合 POJO,但要求字段可访问且无循环引用)
- 避免在 clone() 中抛异常,建议捕获并包装为 RuntimeException,简化调用方处理
不推荐:直接用 Object.clone() 做深拷贝
super.clone() 永远是浅拷贝,它不会自动递归调用子对象的 clone()。想靠它“自动深拷”是常见误解。必须显式控制每层引用的复制逻辑。
深拷贝本质是“重建对象图”,没有银弹。选哪种方式,取决于对象结构稳定性、性能要求和是否允许序列化依赖。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











