深拷贝和浅拷贝区别
区别
- 浅拷贝(Shallow Copy):
- 复制对象时,只复制基本类型字段的值,引用类型字段复制引用地址(指向同一对象)。
- 深拷贝(Deep Copy):
- 复制对象时,基本类型和引用类型字段都创建新副本,生成完全独立的对象。
核心点
- 浅拷贝:修改副本的引用字段会影响原对象。
- 深拷贝:副本与原对象互不影响。
1. 区别详解
(1) 定义
- 浅拷贝:
- 复制一层,引用字段仍指向原对象。
- 深拷贝:
- 递归复制所有层,包含引用字段的完整内容。
(2) 复制内容
- 浅拷贝:
- 基本类型(如
int
、double
):复制值。 - 引用类型(如
List
、Object
):复制地址。 - 深拷贝:
- 基本类型:复制值。
- 引用类型:递归复制对象内容。
(3) 影响
- 浅拷贝:
- 修改副本的引用字段,原对象同步变化。
- 深拷贝:
- 修改副本,原对象不受影响。
示例
class Person implements Cloneable {
int age; // 基本类型
List<String> hobbies; // 引用类型
Person(int age, List<String> hobbies) {
this.age = age;
this.hobbies = hobbies;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 默认浅拷贝
}
}
// 测试
List<String> hobbies = new ArrayList<>(Arrays.asList("reading"));
Person p1 = new Person(25, hobbies);
// 浅拷贝
Person p2 = (Person) p1.clone();
p2.age = 30; // 修改基本类型
p2.hobbies.add("gaming"); // 修改引用类型
System.out.println(p1.age); // 25
System.out.println(p1.hobbies); // [reading, gaming]
System.out.println(p2.age); // 30
System.out.println(p2.hobbies); // [reading, gaming]
// 深拷贝(手动实现)
Person p3 = new Person(p1.age, new ArrayList<>(p1.hobbies));
p3.age = 35;
p3.hobbies.add("swimming");
System.out.println(p1.age); // 25
System.out.println(p1.hobbies); // [reading, gaming]
System.out.println(p3.age); // 35
System.out.println(p3.hobbies); // [reading, swimming]
2. 实现方式
浅拷贝
clone()
方法:- 默认浅拷贝,需实现
Cloneable
。 - 构造器复制:
- 手动赋值字段。
- 对象赋值:
Object.assign()
(JavaScript 示例,非 Java)。
深拷贝
- 手动递归复制:
- 复制引用字段时创建新对象。
Person deepCopy() {
return new Person(this.age, new ArrayList<>(this.hobbies));
}
- 序列化:
- 通过
Serializable
,序列化后反序列化。
public Object deepCopy() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
- 第三方库:
- 如 Gson、Jackson 转 JSON 再还原。
3. 特点对比
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
复制深度 | 一层 | 所有层 |
引用字段 | 复制地址 | 复制内容 |
性能 | 快(少复制) | 慢(全复制) |
内存 | 占用少 | 占用多 |
独立性 | 不完全独立 | 完全独立 |
4. 延伸与面试角度
- 适用场景:
- 浅拷贝:简单对象,引用字段无需独立(如配置)。
- 深拷贝:复杂对象,需隔离(如对象克隆)。
- 注意事项:
- 浅拷贝:引用修改需谨慎。
- 深拷贝:循环引用需处理(如序列化)。
- 实际应用:
- 浅拷贝:
ArrayList
的clone()
。 - 深拷贝:对象备份、原型模式。
- 面试点:
- 问“区别”时,提引用字段影响。
- 问“实现”时,提序列化。
总结
浅拷贝只复制一层,引用字段共享;深拷贝全复制,独立性强。浅拷贝快但不安全,深拷贝慢但可靠。面试时,可写代码或提场景(如原型模式),展示理解深度。