深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是Java面试中考察「对象复制」的高频考点,核心区别在于是否复制引用类型成员的底层对象。
一、核心结论

| 类型 | 复制范围 | 引用类型成员处理 | 核心特点 |
|---|---|---|---|
| 浅拷贝 | 仅复制对象本身,不复制引用类型成员指向的对象 | 引用类型成员仅复制"引用地址",新旧对象共享同一个底层对象 | 拷贝速度快,存在"修改一个影响另一个"的风险 |
| 深拷贝 | 复制对象本身 + 所有引用类型成员指向的对象 | 引用类型成员复制"底层对象",新旧对象完全独立 | 拷贝速度慢,新旧对象互不影响 |
二、通俗理解(用"文件夹"比喻讲透)
把对象想象成一个「文件夹」,里面既有「文件」(基本类型成员,如int/String),也有「子文件夹快捷方式」(引用类型成员,如User/数组):
- 浅拷贝:复制一个新文件夹,里面的文件直接复制,子文件夹只复制"快捷方式"(指向原文件夹)。修改新文件夹里的子文件夹内容,原文件夹的子文件夹也会变;
- 深拷贝:复制一个新文件夹,里面的文件+子文件夹(包括子文件夹里的所有内容)都完整复制。修改新文件夹的任何内容,都不会影响原文件夹。
三、原理分析
1. 浅拷贝的底层逻辑
-
实现方式:实现
Cloneable接口,重写Object类的clone()方法(默认浅拷贝); -
复制规则:
-
- 基本类型成员(int/boolean/char等):复制值(新对象有独立副本);
- 引用类型成员(对象/数组/集合等):复制引用地址(新旧对象指向同一个底层对象)。
2. 深拷贝的底层逻辑
-
实现方式:在浅拷贝基础上,对所有引用类型成员递归调用拷贝方法,或通过序列化实现;
-
复制规则:
-
- 基本类型成员:复制值;
- 引用类型成员:创建新的底层对象,复制其所有内容(新旧对象的引用类型成员指向不同底层对象)。
四、代码演示
先定义基础类(包含引用类型成员)
java
// 引用类型成员类(地址)
class Address {
private String city;
public Address(String city) {
this.city = city;
}
// get/set方法
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
}
// 待拷贝的主类
class Person implements Cloneable {
private String name; // 基本类型(String是不可变类,特殊的引用类型)
private int age; // 基本类型
private Address addr; // 引用类型成员
public Person(String name, int age, Address addr) {
this.name = name;
this.age = age;
this.addr = addr;
}
// get/set方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public Address getAddr() { return addr; }
public void setAddr(Address addr) { this.addr = addr; }
// ===== 1. 浅拷贝实现(默认clone())=====
@Override
protected Object clone() throws CloneNotSupportedException {
// 调用Object的clone(),默认浅拷贝
return super.clone();
}
// ===== 2. 深拷贝实现(手动处理引用类型成员)=====
protected Object deepClone() throws CloneNotSupportedException {
// 第一步:浅拷贝当前对象
Person clonePerson = (Person) super.clone();
// 第二步:对引用类型成员单独拷贝(创建新的Address对象)
clonePerson.addr = new Address(clonePerson.addr.getCity());
return clonePerson;
}
}
测试浅拷贝
java
public class CopyDemo {
public static void main(String[] args) throws CloneNotSupportedException {
// 1. 创建原对象
Address addr = new Address("北京");
Person p1 = new Person("张三", 20, addr);
// 2. 浅拷贝得到p2
Person p2 = (Person) p1.clone();
// 3. 修改p2的引用类型成员(addr)
p2.getAddr().setCity("上海");
// 4. 结果:p1的addr也被修改(共享底层对象)
System.out.println("p1的地址:" + p1.getAddr().getCity()); // 输出:上海
System.out.println("p2的地址:" + p2.getAddr().getCity()); // 输出:上海
// 补充:基本类型成员互不影响(浅拷贝复制了值)
p2.setAge(25);
System.out.println("p1的年龄:" + p1.getAge()); // 输出:20
System.out.println("p2的年龄:" + p2.getAge()); // 输出:25
}
}
测试深拷贝(解决浅拷贝问题)
java
public class CopyDemo {
public static void main(String[] args) throws CloneNotSupportedException {
// 1. 创建原对象
Address addr = new Address("北京");
Person p1 = new Person("张三", 20, addr);
// 2. 深拷贝得到p2
Person p2 = (Person) p1.deepClone();
// 3. 修改p2的引用类型成员(addr)
p2.getAddr().setCity("上海");
// 4. 结果:p1的addr不变(新旧对象独立)
System.out.println("p1的地址:" + p1.getAddr().getCity()); // 输出:北京
System.out.println("p2的地址:" + p2.getAddr().getCity()); // 输出:上海
}
}
五、深拷贝的其他实现方式
方式1:序列化(推荐,适合复杂对象)
通过序列化将对象转为字节流,再反序列化生成新对象(自动实现深拷贝):
java
class Person implements Serializable {
private String name;
private int age;
private Address addr; // Address也需实现Serializable
// 深拷贝方法(序列化)
public Person deepCloneBySerialize() throws IOException, ClassNotFoundException {
// 1. 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 2. 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
}
}
方式2:手动new对象(简单场景)
直接创建新对象,逐个赋值(包括引用类型成员):
java
Person p2 = new Person(p1.getName(), p1.getAge(), new Address(p1.getAddr().getCity()));
六、追问
追问1:String 是引用类型,为什么浅拷贝时修改不会互相影响?
答:String 是「不可变类」------修改 String 本质是创建新的 String 对象,而非修改原有对象内容。因此浅拷贝时,新旧对象的 String 成员指向不同的新对象,不会互相影响。
追问2:浅拷贝有什么应用场景?
答:浅拷贝速度快、开销小,适合以下场景:
- 对象中无引用类型成员;
- 引用类型成员是不可变类(如 String/Integer);
- 不需要修改引用类型成员的场景。
追问3:深拷贝的优缺点?
答:
- 优点:新旧对象完全独立,无修改互相影响的风险;
- 缺点:拷贝速度慢、内存开销大(需复制所有引用类型成员的底层对象),递归拷贝可能导致栈溢出(复杂对象)。
追问:请说说深拷贝和浅拷贝的区别?
答:
- 核心区别:浅拷贝仅复制对象本身和基本类型成员的值,引用类型成员仅复制引用地址(新旧对象共享底层对象);深拷贝不仅复制对象本身,还会复制所有引用类型成员的底层对象(新旧对象完全独立);
- 表现差异:浅拷贝时修改引用类型成员,原对象会受影响;深拷贝时修改任何成员,原对象都不受影响;
- 实现方式:
-
- 浅拷贝:实现 Cloneable 接口,重写 Object.clone();
- 深拷贝:递归拷贝引用类型成员、序列化/反序列化、手动new对象;
- 适用场景:浅拷贝适合无引用类型成员或引用类型为不可变类的场景(效率高);深拷贝适合需要完全隔离新旧对象的场景(如多线程修改、对象持久化)。
总结
- 核心区别:是否复制引用类型成员的底层对象(浅拷贝不复制,深拷贝复制);
- 关键表现:浅拷贝共享引用类型底层对象,深拷贝完全独立;
- 实现方式:浅拷贝用 clone(),深拷贝用递归/序列化/手动new;
- 面试关键:结合「哈希表/多线程」场景说明深拷贝的必要性,体现实战理解。
简单说:浅拷贝是"复制快捷方式",深拷贝是"复制全部内容"~