外观
深拷贝和浅拷贝的区别
⭐ 题目日期:
美团 - 2025/4/25
📝 题解:
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是编程中复制对象的两种方式,核心区别在于是否递归复制嵌套对象:
特性 | 浅拷贝 (Shallow Copy) | 深拷贝 (Deep Copy) |
---|---|---|
复制内容 | 仅复制对象本身(顶层属性) | 递归复制对象及其所有嵌套对象 |
引用类型属性 | 新旧对象共享同一引用(指向相同内存地址) | 为新对象创建全新的嵌套副本(内存地址不同) |
修改影响 | 修改嵌套对象会影响原对象 | 修改嵌套对象不会影响原对象 |
内存开销 | 小 | 大(尤其嵌套层级深时) |
性能 | 快 | 慢 |
典型场景 | 简单对象、无需独立嵌套数据时 | 需要完全独立的对象副本时 |
不同语言的实现示例
1. Python
import copy
original = [[1, 2], [3, 4]]
# 浅拷贝
shallow = copy.copy(original) # 或 original.copy() / list(original)
shallow[0][0] = 99
print(original) # [[99, 2], [3, 4]] → 原对象被修改!
# 深拷贝
deep = copy.deepcopy(original)
deep[0][0] = 100
print(original) # [[99, 2], [3, 4]] → 原对象不变
2. Java
import org.apache.commons.lang3.SerializationUtils;
// 浅拷贝
List<List<Integer>> original = new ArrayList<>(Arrays.asList(
new ArrayList<>(Arrays.asList(1, 2)),
new ArrayList<>(Arrays.asList(3, 4))
));
List<List<Integer>> shallow = new ArrayList<>(original); // 浅拷贝
shallow.get(0).set(0, 99);
System.out.println(original); // [[99, 2], [3, 4]] → 原对象被修改!
// 深拷贝(需对象实现 Serializable)
List<List<Integer>> deep = SerializationUtils.clone(original);
deep.get(0).set(0, 100);
System.out.println(original); // [[99, 2], [3, 4]] → 原对象不变
3. JavaScript
const original = [[1, 2], [3, 4]];
// 浅拷贝
const shallow = [...original]; // 或 Array.from(original)
shallow[0][0] = 99;
console.log(original); // [[99, 2], [3, 4]] → 原对象被修改!
// 深拷贝
const deep = JSON.parse(JSON.stringify(original)); // 注意:不支持函数/日期等
deep[0][0] = 100;
console.log(original); // [[99, 2], [3, 4]] → 原对象不变
4. C++
#include <vector>
#include <memory>
// 深拷贝示例
std::vector<std::vector<int>> original = {{1, 2}, {3, 4}};
std::vector<std::vector<int>> deep = original; // 默认深拷贝(值语义)
deep[0][0] = 100;
// original 保持不变
// 浅拷贝需用指针(需手动管理内存)
std::vector<std::vector<int>*> shallow;
for (auto& inner : original) {
shallow.push_back(&inner); // 指向原对象内存
}
(*shallow[0])[0] = 99; // 修改会影响 original
5. Go
package main
import (
"fmt"
"gopkg.in/yaml.v3" // 或 encoding/json
)
func main() {
original := [][]int{{1, 2}, {3, 4}}
// 浅拷贝
shallow := make([][]int, len(original))
copy(shallow, original) // 仅复制外层切片
shallow[0][0] = 99
fmt.Println(original) // [[99 2] [3 4]] → 原对象被修改!
// 深拷贝(通过序列化)
var deep [][]int
data, _ := yaml.Marshal(original)
yaml.Unmarshal(data, &deep)
deep[0][0] = 100
fmt.Println(original) // [[99 2] [3 4]] → 原对象不变
}
关键总结
- 浅拷贝:适合简单对象(无嵌套引用),效率高,但修改嵌套数据会污染原对象。
- 深拷贝:创建完全隔离的副本,安全但耗资源,需注意循环引用问题(如 Python 的
deepcopy
可处理)。 - 语言差异:
- Python/JS/Java 默认赋值是引用传递,需显式浅/深拷贝。
- C++/Go 值类型默认深拷贝,引用类型需特别注意。
- 深拷贝实现常依赖序列化(
JSON
/pickle
)或库函数。
根据需求选择拷贝方式:若对象不可变或无需修改嵌套数据,浅拷贝更高效;若需完全独立副本,务必深拷贝。