深拷贝和浅拷贝区别
1. 浅拷贝 (Shallow Copy)
浅拷贝会创建一个新对象,然后将原始对象中的所有字段的值,原封不动地复制到新对象中。
-
对于基本数据类型(如 int, double, boolean 等),浅拷贝会直接复制它们的值。修改新对象的基本类型字段,不会影响原始对象。
-
对于引用数据类型(如 String, Array, 或者其他自定义类的对象),浅拷贝只会复制这个引用的地址值,而不会复制引用所指向的那个实际的对象。
这就导致一个关键结果:原始对象和浅拷贝出的新对象,其内部的引用类型成员变量,指向的是堆内存中同一个对象。
2. 深拷贝 (Deep Copy)
深拷贝为了解决浅拷贝的问题而产生。它同样会创建一个新对象,但在处理引用类型成员变量时,它不是简单地复制引用地址,而是会递归地创建所有引用对象的新副本。
-
对于基本数据类型,深拷贝和浅拷贝的行为是一样的,都是值复制。
-
对于引用数据类型,深拷贝会创建一个新的、与原始对象内容相同的对象,然后将新对象的引用地址赋给拷贝出对象的成员变量。
这样做的结果是:原始对象和深拷贝出的新对象,它们内部的所有引用类型成员,都指向了各自独立的、互不相关的对象。
| 特性 | 浅拷贝 (Shallow Copy) | 深拷贝 (Deep Copy) |
|---|---|---|
| 基本类型 | 复制值 | 复制值 |
| 引用类型 | 复制引用地址(指针) | 递归创建并复制对象内容 |
| 对象关系 | 原始对象和拷贝对象共享引用类型的成员对象 | 原始对象和拷贝对象的所有成员都是独立的 |
| 隔离性 | 差,修改拷贝对象的引用成员会影响原始对象 | 好,对象之间完全独立,互不影响 |
实现方式
-
实现浅拷贝:
- 最常见的方式是实现 Cloneable 接口,并重写 Object 类的 clone() 方法。默认的 Object.clone() 实现就是一种浅拷贝。
-
实现深拷贝:
-
重写clone()方法:在重写 clone() 方法时,除了调用 super.clone() 得到一个浅拷贝的对象外,还需要手动地为所有引用类型的成员变量也调用它们的 clone() 方法,进行递归拷贝。这要求所有引用类型也都要正确地实现深拷贝。
-
通过序列化:这是一个巧妙且常用的方法。将原始对象通过对象输出流(ObjectOutputStream)写入到一个字节数组输出流中,然后再从这个字节数组输出流中通过对象输入流(ObjectInputStream)读出一个新的对象。这个过程会创建一个完整的对象图的副本,从而实现彻底的深拷贝。所有涉及的对象都需要实现 Serializable 接口。这种方法代码简单,但性能开销相对较大。
-