Skip to content

深拷贝和浅拷贝区别

1. 浅拷贝 (Shallow Copy)

浅拷贝会创建一个新对象,然后将原始对象中的所有字段的值,原封不动地复制到新对象中。

  • 对于基本数据类型(如 int, double, boolean 等),浅拷贝会直接复制它们的值。修改新对象的基本类型字段,不会影响原始对象。

  • 对于引用数据类型(如 String, Array, 或者其他自定义类的对象),浅拷贝只会复制这个引用的地址值,而不会复制引用所指向的那个实际的对象。

这就导致一个关键结果:原始对象和浅拷贝出的新对象,其内部的引用类型成员变量,指向的是堆内存中同一个对象。

2. 深拷贝 (Deep Copy)

深拷贝为了解决浅拷贝的问题而产生。它同样会创建一个新对象,但在处理引用类型成员变量时,它不是简单地复制引用地址,而是会递归地创建所有引用对象的新副本。

  • 对于基本数据类型,深拷贝和浅拷贝的行为是一样的,都是值复制。

  • 对于引用数据类型,深拷贝会创建一个新的、与原始对象内容相同的对象,然后将新对象的引用地址赋给拷贝出对象的成员变量。

这样做的结果是:原始对象和深拷贝出的新对象,它们内部的所有引用类型成员,都指向了各自独立的、互不相关的对象。

特性 浅拷贝 (Shallow Copy) 深拷贝 (Deep Copy)
基本类型 复制值 复制值
引用类型 复制引用地址(指针) 递归创建并复制对象内容
对象关系 原始对象和拷贝对象共享引用类型的成员对象 原始对象和拷贝对象的所有成员都是独立的
隔离性 差,修改拷贝对象的引用成员会影响原始对象 好,对象之间完全独立,互不影响

实现方式

  1. 实现浅拷贝:

    • 最常见的方式是实现 Cloneable 接口,并重写 Object 类的 clone() 方法。默认的 Object.clone() 实现就是一种浅拷贝。
  2. 实现深拷贝:

    • 重写clone()方法:在重写 clone() 方法时,除了调用 super.clone() 得到一个浅拷贝的对象外,还需要手动地为所有引用类型的成员变量也调用它们的 clone() 方法,进行递归拷贝。这要求所有引用类型也都要正确地实现深拷贝。

    • 通过序列化:这是一个巧妙且常用的方法。将原始对象通过对象输出流(ObjectOutputStream)写入到一个字节数组输出流中,然后再从这个字节数组输出流中通过对象输入流(ObjectInputStream)读出一个新的对象。这个过程会创建一个完整的对象图的副本,从而实现彻底的深拷贝。所有涉及的对象都需要实现 Serializable 接口。这种方法代码简单,但性能开销相对较大。