Skip to content

深拷贝和浅拷贝的区别

约 822 字大约 3 分钟

语言基础类美团

2025-07-10

⭐ 题目日期:

美团 - 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)或库函数。

根据需求选择拷贝方式:若对象不可变或无需修改嵌套数据,浅拷贝更高效;若需完全独立副本,务必深拷贝。