# 简介

  • 浅拷贝:对基本数据类型进行值的传递,对引用数据类型进行引用传递的拷贝;
  • 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容;

    # 浅拷贝

    首先创建一个 Parent 类和 Child 类,实现浅拷贝只需要让 Parent 类继承 Cloneable 接口,并且重写clone() 方法。 ```java public class Parent implements Cloneable { String parentName; Child child;

    public Parent(String parentName, Child child) {

    1. this.parentName = parentName;
    2. this.child = child;

    }

    @Override protected Object clone() throws CloneNotSupportedException {

    1. return super.clone();

    } }

public class Child { String childName;

  1. public Child(String childName) {
  2. this.childName = childName;
  3. }

}

  1. ```java
  2. public class Test {
  3. public static void main(String[] args) throws CloneNotSupportedException {
  4. Parent parent1 = new Parent("parent name", new Child("child name"));
  5. Parent parent2 = (Parent) parent1.clone();
  6. System.out.println(parent1 == parent2);
  7. System.out.println("parent1: " + parent1.hashCode());
  8. System.out.println("parent2: " + parent2.hashCode());
  9. System.out.println("==============");
  10. System.out.println(parent1.child == parent2.child);
  11. System.out.println("child1: " + parent1.child.hashCode());
  12. System.out.println("child2: " + parent2.child.hashCode());
  13. System.out.println(parent1.child.childName);
  14. System.out.println(parent2.child.childName);
  15. }
  16. }
  1. false
  2. parent1: 1456208737
  3. parent2: 25126016
  4. parent name
  5. parent name
  6. ==============
  7. true
  8. child1: 762218386
  9. child2: 762218386
  10. child name
  11. child name

通过 hashCode() 和 == 我们可以发现,浅拷贝确实创建了一个新的对象。但是对于引用类型的属性child 而言,从 hashCode() 可以发现浅拷贝过后仍然引用了相同的 Child 对象,即浅拷贝只传递了属性为引用类型的引用。

# 深拷贝

常用实现深拷贝的方案有两种:

  • 序列化这个对象,再反序列化回来,就可以得到这个新的对象。
  • 继续利用 clone() 方法,让属性实现 Cloneable 接口。

    | 属性实现 Cloneable 接口

    和之前的浅拷贝不同之处在于这里 Child 也实现了 Cloneable,并重写了 clone() 方法,而 Parent 的clone() 方法也有略微不同,在调用了 clone() 方法后还调用了属性 child 的 clone() 方法重新设置属性,实现完全的拷贝。 ```java public class Parent implements Cloneable { String parentName; Child child;

    public Parent(String parentName, Child child) {

    1. this.parentName = parentName;
    2. this.child = child;

    }

    @Override protected Object clone() throws CloneNotSupportedException {

    1. Parent parentclone = (Parent) super.clone();
    2. parentclone.child = (Child) this.child.clone();
    3. return parentclone;

    } }

public class Child implements Cloneable { String childName;

  1. public Child(String childName) {
  2. this.childName = childName;
  3. }
  4. @Override
  5. protected Object clone() throws CloneNotSupportedException {
  6. return super.clone();
  7. }

}

  1. ```java
  2. false
  3. parent1: 1456208737
  4. parent2: 25126016
  5. parent name
  6. parent name
  7. ==============
  8. false
  9. child1: 762218386
  10. child2: 672320506
  11. child name
  12. child name

通过 hashCode() 可以发现,原始对象和拷贝对象的属性 child 已经是两个不同的对象。

| 序列化

两个类都不需要再实现 Cloneable 接口并重写 clone() 方法了,但是它们都需要实现 Serializable 接口,并且在 Parent 的克隆方法中要实现序列化反序列化的逻辑。

  1. public class Parent implements Serializable {
  2. String parentName;
  3. Child child;
  4. public Parent(String parentName, Child child) {
  5. this.parentName = parentName;
  6. this.child = child;
  7. }
  8. public Object deepClone() throws Exception {
  9. // 将对象写到流里
  10. OutputStream bo = new ByteArrayOutputStream();
  11. ObjectOutputStream oo = new ObjectOutputStream(bo);
  12. oo.writeObject(this);
  13. // 从流里读对象出来
  14. // toByteArray()创建一个新分配的字节数组。数组的大小和当前输出流的大小,内容是当前输出流的拷贝。
  15. InputStream bi = new ByteArrayInputStream(((ByteArrayOutputStream) bo).toByteArray());
  16. ObjectInputStream oi = new ObjectInputStream(bi);
  17. return oi.readObject();
  18. }
  19. }
  20. public class Child implements Serializable {
  21. String childName;
  22. public Child(String childName) {
  23. this.childName = childName;
  24. }
  25. }
  1. false
  2. parent name
  3. parent name
  4. ==================
  5. false
  6. child name
  7. child name

# 引用拷贝

引用拷贝指的是两个不同的引用指向同一个对象。
image.png

# 参考

  1. Java中的深拷贝与浅拷贝-水木今山的博客
  2. 细说 Java 的深拷贝和浅拷贝
  3. 菜鸟教程-ByteArrayOutputStream类
  4. JavaGuide