1.核心区别
深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 是对象复制的两种核心方式,主要区别在于对 引用类型字段 的处理
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
对象复制范围 | 只复制对象本身(基本类型字段 + 引用地址) | 递归复制对象及其引用的所有子对象 |
引用类型字段 | 仅复制引用地址(新旧对象共享同一对象) | 创建全新独立对象(无共享) |
内存关系 | 原对象和拷贝对象部分共享内存 | 完全独立的内存空间 |
修改影响 | 修改引用字段会影响原对象 | 修改引用字段 不影响 原对象 |
默认实现 | Object.clone() 默认行为 | 需手动实现 |
性能 | 快(仅复制一层) | 慢(递归复制整个对象树) |
例如:对象是一本书,浅拷贝就是把目录复制了一份,而深拷贝是吧整本书复制了一份。
2.技术细节解析
java
class Address implements Cloneable {
String city;
public Address(String city) {
this.city = city;
}
// 浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable {
String name;
Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// 深拷贝
protected Person deepClone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) address.clone(); // 关键:拷贝引用对象
return cloned;
}
}
public class CopyDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr = new Address("Beijing");
Person p1 = new Person("Tom", addr);
// 浅拷贝
Person p2 = (Person) p1.clone();
// 深拷贝
Person p3 = p1.deepClone();
// 修改原始对象的引用类型字段
p1.address.city = "Shanghai";
System.out.println("p2.address.city (浅拷贝): " + p2.address.city); // 输出 Shanghai
System.out.println("p3.address.city (深拷贝): " + p3.address.city); // 输出 Beijing
}
}
使用序列化实现深拷贝
java
import java.io.*;
public class DeepCopyUtil {
public static <T extends Serializable> T deepCopy(T object) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(object); // 序列化
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject(); // 反序列化生成新对象
}
} catch (Exception e) {
throw new RuntimeException("Deep copy failed", e);
}
}
}
// 使用
Person deepCopy = DeepCopyUtil.deepCopy(original);
deepCopy.address.setCity("Tokyo");
System.out.println(original.address.getCity()); // 输出 "Paris"(原对象不受影响)
3.关键使用场景
场景 | 推荐方式 | 原因 |
---|---|---|
对象不含引用类型字段 | 浅拷贝 | 性能高且安全 |
引用字段是不可变对象 | 浅拷贝 | String/包装类等不可变对象无需深拷贝 |
对象包含可变引用字段 | 深拷贝 | 避免意外修改原对象 |
复杂嵌套对象图 | 序列化深拷贝 | 避免递归实现的复杂性 |
4.注意事项
-
Cloneable 接口的缺陷:
是标记接口(无方法),但必须实现才能调用 Object.clone()
clone() 方法是 protected,需重写为 public
-
深拷贝陷阱:
递归实现需确保所有嵌套对象都支持克隆
循环引用会导致递归无限循环(序列化可解决)
-
最佳实践:
优先使用 不可变对象(如 String、LocalDateTime)
复杂对象推荐用 序列化法 实现深拷贝
避免深拷贝:考虑用 防御性拷贝构造器(如 new ArrayList<>(originalList))
💡 终极原则:如果对象需要完全隔离修改,用深拷贝;如果共享数据无风险或用不可变对象,用浅拷贝。