Java中对象的浅拷贝与深拷贝实现及差异
Java中直接通过赋值操作(如 Person b = a;)仅复制对象引用地址,导致两个变量指向堆中同一实例。修改任一变量的属性将影响对方。为避免此问题,需使用拷贝机制——核心是实现 Object 类的 clone() 方法,或借助序列化技术生成独立副本。
浅拷贝(Shallow Copy)
浅拷贝仅创建新对象自身,但若字段为引用类型,则拷贝其引用地址,即:新旧对象共享嵌套对象。
实现浅拷贝需满足:
- 类实现 Cloneable 接口(标记接口,避免抛出 CloneNotSupportedException);
- 重写 clone() 方法并设为 public。
示例:包含基本类型字段和引用类型字段的类 People。
public class Car implements Cloneable {
private String name;
private String color;
// getter & setter 省略
@Override
public Car clone() throws CloneNotSupportedException {
return (Car) super.clone();
}
}
public class People implements Cloneable {
private String name;
private int age;
private Car car;
// getter & setter 省略
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // 仅 copy 当前对象基本类型字段,引用字段仍共享
}
@Override
public String toString() {
return "People{name='" + name + "', age=" + age + ", car=" + car + "}";
}
}
测试代码及输出:
public static void main(String[] args) throws Exception {
People p1 = new People();
p1.setName("zhangsan");
p1.setAge(23);
Car c = new Car();
c.setName("Ferrari");
c.setColor("red");
p1.setCar(c);
People p2 = (People) p1.clone();
System.out.println("p1: " + p1);
System.out.println("p2: " + p2);
// 输出:
// p1: People{name='zhangsan', age=23, car=Car@abc123}
// p2: People{name='zhangsan', age=23, car=Car@abc123}
// 地址相同 → 共享嵌套对象
}
验证:修改 p2.car 的颜色,p1.car 也跟着变化,证明两者共享同一 Car 实例。
深拷贝(Deep Copy)
深拷贝需递归复制所有层级的引用对象,确保新对象与原对象完全独立。可采用以下两种方式:
方式一:手动实现(重写嵌套对象的 clone)
对 People 的 clone 方法进行扩展,显式 clone 其引用字段:
public class Car implements Cloneable {
// ...同上
}
public class People implements Cloneable {
// ...字段同上
@Override
public Object clone() throws CloneNotSupportedException {
People cloned = (People) super.clone();
cloned.setCar(car.clone()); // 关键:逐级克隆引用对象
return cloned;
}
}
测试结果:p1.car 与 p2.car 地址不同,互不影响。
方式二:基于序列化实现深拷贝
该方式不依赖手动递归,适用于多层嵌套或复杂对象结构,前提是所有相关类均实现 Serializable 接口。
import java.io.*;
public class DeepCloneUtil {
public static <T extends Serializable> T deepClone(T obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
}
}
调用示例:
People original = ...; // 已初始化
People copy = DeepCloneUtil.deepClone(original);
// copy 中嵌套对象均非原对象引用,地址唯一
序列化法优势:
- 无需为每个类实现 Cloneable 和重写 clone();
- 支持任意深度的对象图拷贝;
- 更健壮,不易因遗漏引用字段导致浅拷贝。
注意:Spring 或其他框架中的代理对象、transient 字段、非序列化依赖项需特殊处理。