Java 中 Object 类是所有类的根类,Object 提供一个 clone() 方法,该方法可以将一个 Java 对象复制一份,但是需要实现 clone 的 Java 类必须要实现一个接口 Cloneable,该接口表示该类能够复制且具有复制的能力 =》 原型模式。

原型模式的注意事项和细节

  • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也可以提高效率;
  • 不用重新初始化对象,而是动态的获得对象运行时的状态;
  • 如果原始对象发生变化(增加或减少属性),其他克隆对象也会发生相应的变化,无需求该代码
  • 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则。

Sheep 重写 clone.

  1. public class Sheep implements Cloneable{
  2. private String name;
  3. private int age;
  4. private String color;
  5. public Sheep() {
  6. }
  7. public Sheep(String name, int age, String color) {
  8. this.name = name;
  9. this.age = age;
  10. this.color = color;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public String getColor() {
  25. return color;
  26. }
  27. public void setColor(String color) {
  28. this.color = color;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Sheep{" +
  33. "name='" + name + '\'' +
  34. ", age=" + age +
  35. ", color='" + color + '\'' +
  36. '}';
  37. }
  38. // 使用默认的 clone 方法
  39. // 深拷贝
  40. @Override
  41. protected Object clone(){
  42. Sheep sheep = null;
  43. try {
  44. sheep = (Sheep) super.clone();
  45. } catch (CloneNotSupportedException e) {
  46. e.printStackTrace();
  47. }
  48. return sheep;
  49. }
  50. }

两个对象属性是一样的,但是 hashCode 不相等。

public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep1 = (Sheep) sheep.clone();
        System.out.println(sheep1);
        System.out.println(sheep.hashCode());
        System.out.println(sheep1.hashCode());
    }
}

深拷贝 & 浅拷贝

将上面那个例子改一下

public class Sheep implements Cloneable{

    private String name;

    private int age;

    private String color;

    private Sheep friend;


    public Sheep() {
    }

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Sheep getFriend() {
        return friend;
    }

    public void setFriend(Sheep friend) {
        this.friend = friend;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                ", friend=" + friend +
                '}';
    }

    // 使用默认的 clone 方法
    // 深复制
    @Override
    protected Object  clone(){
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }
}
public class Client {

    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        sheep.setFriend(new Sheep("jack", 2, "黑色"));

        Sheep sheep1 = (Sheep) sheep.clone();
        Sheep sheep2 = (Sheep) sheep.clone();

        System.out.println("sheep1 " + sheep1.hashCode() + " sheep1.friend " + sheep1.getFriend().hashCode());
        System.out.println("sheep2 " + sheep2.hashCode() + " sheep2.friend " + sheep2.getFriend().hashCode());
    }
}

输出:

sheep1 1627674070 sheep1.friend 1360875712
sheep2 1625635731 sheep2.friend 1360875712

总结: 这边的 friend 只是浅拷贝,将内存地址指向第一个 sheep 对象。重写 clone 方法会深拷贝,重新生成一个对象,重新开辟一块内存空间。

深拷贝 - 序列化反序列化实现

 // 深拷贝2
public Object deepClone() {
    ByteArrayOutputStream bos = null;
    ObjectOutputStream oos = null;

    ByteArrayInputStream bis = null;
    ObjectInputStream ois = null;
    try {
        // 序列化
        bos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream(bos);
        oos.writeObject(this); //当前这个对象以对象流的方式输出
        // 反序列化
        bis = new ByteArrayInputStream(bos.toByteArray());
        ois = new ObjectInputStream(bis);
        DeepProtoType deepProtoType = (DeepProtoType) ois.readObject();
        return deepProtoType;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    } finally {
        try {
            bos.close();
            oos.close();
            bis.close();
            ois.close();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}