返回
深浅对比,一文带你掌握浅拷贝与深拷贝
前端
2022-11-21 08:20:01
浅拷贝与深拷贝:对象拷贝的基本原理
在编程世界中,对象拷贝是一种常见而关键的操作。它允许你创建对象的新副本,从而实现数据的隔离和共享。根据拷贝的深度,对象拷贝可以分为浅拷贝和深拷贝。
浅拷贝:浅尝辄止的拷贝
浅拷贝只复制对象本身的数据,而不会复制它所引用的其他对象。这就好比把一个装着文件的文件夹复制了一份,而没有复制文件夹里的文件。结果就是,浅拷贝后的副本与原对象指向相同的子对象。如果原对象所引用的子对象发生变化,则副本中的子对象也会随之变化。
深拷贝:彻底彻底的拷贝
深拷贝则完全不同。它会递归地复制对象及其所引用的所有子对象。这就好比把文件夹及其所有文件都复制了一份。结果就是,深拷贝后的副本与原对象完全独立,互不影响。即使原对象所引用的子对象发生变化,副本中的子对象也不会受到影响。
浅拷贝与深拷贝的应用场景
浅拷贝和深拷贝各有其适用的场景。一般来说,浅拷贝适合用于以下情况:
- 当对象之间没有循环引用时,就像把文件夹复制出来不会造成无限循环一样。
- 当对象所引用的子对象不需要隔离时,就像你不介意其他人修改你复制出来的文件夹里的文件一样。
- 当对象所引用的子对象很少时,就像文件夹里只有几份文件,复制起来很容易一样。
深拷贝适合用于以下情况:
- 当对象之间存在循环引用时,就像一个文件夹里包含着指向自己的链接一样。
- 当对象所引用的子对象需要隔离时,就像你不想让别人修改你复制出来的文件夹里的文件一样。
- 当对象所引用的子对象很多时,就像文件夹里塞满了文件,复制起来比较麻烦一样。
浅拷贝与深拷贝的实现方法
在不同的编程语言中,实现浅拷贝和深拷贝的方法有所不同。以下是一些常见的实现方法:
- Python :使用
copy.copy()
函数进行浅拷贝,copy.deepcopy()
函数进行深拷贝。 - Java :使用
clone()
方法进行浅拷贝,使用Serializable
接口和ObjectOutputStream/ObjectInputStream
类进行深拷贝。 - C++ :使用赋值运算符
=
进行浅拷贝,使用构造函数或memcpy()
函数进行深拷贝。
代码示例
以下是一些浅拷贝和深拷贝的代码示例:
Python :
class MyClass:
def __init__(self, a, b):
self.a = a
self.b = b
obj1 = MyClass(1, 2)
obj2 = copy.copy(obj1) # 浅拷贝
obj3 = copy.deepcopy(obj1) # 深拷贝
print(obj1.a, obj1.b) # 输出:1 2
print(obj2.a, obj2.b) # 输出:1 2
print(obj3.a, obj3.b) # 输出:1 2
obj1.a = 3
obj1.b = 4
print(obj1.a, obj1.b) # 输出:3 4
print(obj2.a, obj2.b) # 输出:1 2
print(obj3.a, obj3.b) # 输出:1 2
Java :
class MyClass {
private int a;
private int b;
public MyClass(int a, int b) {
this.a = a;
this.b = b;
}
public MyClass clone() {
try {
return (MyClass) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
MyClass obj1 = new MyClass(1, 2);
MyClass obj2 = obj1.clone(); // 浅拷贝
MyClass obj3 = (MyClass) new ObjectInputStream(new ByteArrayInputStream(new ObjectOutputStream().writeObject(obj1))).readObject(); // 深拷贝
System.out.println(obj1.a + "," + obj1.b); // 输出:1, 2
System.out.println(obj2.a + "," + obj2.b); // 输出:1, 2
System.out.println(obj3.a + "," + obj3.b); // 输出:1, 2
obj1.a = 3;
obj1.b = 4;
System.out.println(obj1.a + "," + obj1.b); // 输出:3, 4
System.out.println(obj2.a + "," + obj2.b); // 输出:1, 2
System.out.println(obj3.a + "," + obj3.b); // 输出:1, 2
C++ :
class MyClass {
public:
int a;
int b;
MyClass(int a, int b) {
this->a = a;
this->b = b;
}
MyClass(const MyClass& other) {
this->a = other.a;
this->b = other.b;
}
MyClass& operator=(const MyClass& other) {
this->a = other.a;
this->b = other.b;
return *this;
}
};
MyClass obj1(1, 2);
MyClass obj2 = obj1; // 浅拷贝
MyClass obj3(obj1); // 深拷贝
cout << obj1.a << "," << obj1.b << endl; // 输出:1, 2
cout << obj2.a << "," << obj2.b << endl; // 输出:1, 2
cout << obj3.a << "," << obj3.b << endl; // 输出:1, 2
obj1.a = 3;
obj1.b = 4;
cout << obj1.a << "," << obj1.b << endl; // 输出:3, 4
cout << obj2.a << "," << obj2.b << endl; // 输出:1, 2
cout << obj3.a << "," << obj3.b << endl; // 输出:1, 2
常见问题解答
- 浅拷贝和深拷贝有什么区别?
浅拷贝只复制对象本身的数据,而深拷贝则递归地复制对象及其所引用的所有子对象。 - 什么时候应该使用浅拷贝?
当对象之间没有循环引用,不需要隔离子对象或子对象很少时。 - 什么时候应该使用深拷贝?
当对象之间存在循环引用,需要隔离子对象或子对象很多时。 - 如何实现浅拷贝和深拷贝?
具体方法因编程语言而异,但通常浅拷贝使用赋值或克隆操作,深拷贝使用序列化或递归复制。 - 浅拷贝和深拷贝在性能上有什么区别?
深拷贝通常比浅拷贝慢,因为需要递归复制子对象。