Java 中的**深拷贝(Deep Copy)和浅拷贝(Shallow Copy)**是对象复制时两个非常重要的概念,尤其在涉及引用类型属性时,它们的行为差异会直接影响程序的逻辑和数据安全。
🔹 一、基本概念
概念 | 定义 |
---|---|
浅拷贝 | 创建一个新对象,但对象中的字段 引用原始对象中的字段值(如果是引用类型,共享同一块内存)。 |
深拷贝 | 创建一个新对象,并且对象中的 引用类型字段也会被拷贝成新的对象,彼此互不影响。 |
🔹 二、图示理解
假设有类 Person
包含一个 Address
成员:
Person p1 ──► name: "Tom"
address ──► city: "Shanghai"
浅拷贝后:
Person p2 ──► name: "Tom"
address ──► city: "Shanghai" // 和 p1.address 指向同一个对象
深拷贝后:
Person p2 ──► name: "Tom"
address ──► city: "Shanghai" // 新建了一个 Address 对象,内容一样,但引用不同
🔹 三、示例代码
✅ 1. 浅拷贝:使用 clone()
方法
class Address {
String city;
Address(String city) {
this.city = city;
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 浅拷贝
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr = new Address("Shanghai");
Person p1 = new Person("Tom", addr);
Person p2 = (Person) p1.clone();
p2.address.city = "Beijing"; // 修改 p2 的地址
System.out.println(p1.address.city); // 输出 "Beijing",p1 被影响了
}
}
✅ 2. 深拷贝:手动实现(逐个 clone)
class Address implements Cloneable {
String city;
Address(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return new Address(this.city); // 克隆新对象
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) this.address.clone(); // 深拷贝
return cloned;
}
}
🔹 四、其他深拷贝实现方式
✅ 1. 使用序列化(适用于对象结构复杂的情况)
import java.io.*;
public class DeepClone {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T copy(T obj) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
}
}
缺点:类必须实现
Serializable
接口,性能较低,但优点是通用、结构复杂也能处理。
✅ 2. 使用第三方库
- Apache Commons Lang:
Person copied = SerializationUtils.clone(original);
- Gson 或 Jackson:
Person copied = new Gson().fromJson(new Gson().toJson(original), Person.class);
🔹 五、浅拷贝与深拷贝对比总结
比较项 | 浅拷贝 | 深拷贝 |
---|---|---|
是否新建对象 | 是(主对象) | 是(主对象 + 所有引用对象) |
引用类型字段 | 拷贝引用地址(共享同一个对象) | 拷贝为新对象(内容一样,地址不同) |
影响范围 | 修改引用对象会影响原对象 | 完全独立 |
实现复杂度 | 简单(clone() 或复制构造) | 相对复杂(手动逐层复制) |
适用场景 | 数据变化不敏感;无需隔离 | 数据隔离要求高 |
✅ 结语
- 浅拷贝适合结构简单、对数据引用没影响的场景。
- 深拷贝适合结构复杂或引用对象多、数据相互隔离要求高的业务。
好的,以下是一个 完整 Java 示例,展示了:
- 如何实现浅拷贝
- 如何实现深拷贝
- 两者行为的区别(运行结果可以清楚看出)
✅ 1. 完整 Java 示例代码
import java.io.*;
// 地址类:实现深拷贝需要实现 Cloneable 接口
class Address implements Cloneable, Serializable {
String city;
Address(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return new Address(this.city); // 深拷贝用
}
@Override
public String toString() {
return city;
}
}
// 人类:包含引用类型 Address
class Person implements Cloneable, Serializable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 浅拷贝
protected Person shallowClone() throws CloneNotSupportedException {
return (Person) super.clone(); // Address 仍是引用同一个对象
}
// 深拷贝:手动克隆每一层
protected Person deepClone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) this.address.clone();
return cloned;
}
// 深拷贝:序列化方式
protected Person deepCloneBySerialization() throws IOException, ClassNotFoundException {
// 写入流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// 读取流
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Person) ois.readObject();
}
@Override
public String toString() {
return "Person{name='" + name + "', address=" + address + "}";
}
}
// 测试类
public class CopyDemo {
public static void main(String[] args) throws Exception {
Address address = new Address("Shanghai");
Person p1 = new Person("Tom", address);
System.out.println("原始对象: " + p1);
// 浅拷贝
Person shallow = p1.shallowClone();
shallow.address.city = "Beijing";
System.out.println("\n== 浅拷贝后修改 shallow.address.city = 'Beijing'");
System.out.println("原始对象: " + p1); // 被影响
System.out.println("浅拷贝对象: " + shallow); // 也改了
// 深拷贝
Person deep = p1.deepClone();
deep.address.city = "Guangzhou";
System.out.println("\n== 深拷贝后修改 deep.address.city = 'Guangzhou'");
System.out.println("原始对象: " + p1); // 不被影响
System.out.println("深拷贝对象: " + deep);
// 深拷贝(序列化)
Person deep2 = p1.deepCloneBySerialization();
deep2.address.city = "Shenzhen";
System.out.println("\n== 序列化深拷贝后修改 deep2.address.city = 'Shenzhen'");
System.out.println("原始对象: " + p1); // 不被影响
System.out.println("序列化深拷贝: " + deep2);
}
}
✅ 2. 运行输出示例
原始对象: Person{name='Tom', address=Shanghai}
== 浅拷贝后修改 shallow.address.city = 'Beijing'
原始对象: Person{name='Tom', address=Beijing}
浅拷贝对象: Person{name='Tom', address=Beijing}
== 深拷贝后修改 deep.address.city = 'Guangzhou'
原始对象: Person{name='Tom', address=Beijing}
深拷贝对象: Person{name='Tom', address=Guangzhou}
== 序列化深拷贝后修改 deep2.address.city = 'Shenzhen'
原始对象: Person{name='Tom', address=Beijing}
序列化深拷贝: Person{name='Tom', address=Shenzhen}
🔚 总结重点
方法 | Address 是否独立? | 实现难度 | 说明 |
---|---|---|---|
shallowClone() | ❌ 否,共享引用 | 简单 | 快速但易出问题 |
deepClone() | ✅ 是 | 中等 | 推荐,控制明确 |
deepCloneBySerialization() | ✅ 是 | 较高 | 适合复杂结构、但效率低 |
发表回复