深拷贝的介绍

  1. 复制对象的所有基本数据类型的成员变量值
  2. 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象.也就是说,对象进行深拷贝要对整个对象进行拷贝
  3. 深拷贝实现方式1: 重写clone()方法实现深拷贝
  4. 深拷贝实现方式2: 通过对象序列化实现深拷贝

深拷贝实践

第一种

DeepCloneableTarget

package com.atguigu.prototype.deepclone;

import java.io.Serializable;


public class DeepCloneableTarget implements Serializable,Cloneable {
    /*
     *
     * */
    private static final long serialVersionUID = 1L;

    private String cloneName;

    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    public DeepCloneableTarget() {
        super();
    }

    // 因为该类的属性都是String, 因此我们这里使用默认的clone方法完成即可
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

DeepCloneableTarget

package com.atguigu.prototype.deepclone;

import java.io.Serializable;


public class DeepProtoType implements Serializable,Cloneable {
    public String name; // String 属性
    public DeepCloneableTarget deepCloneableTarget; // 引用类型属性

    public DeepProtoType() {
        super();
    }

    // 深拷贝 -- 方式1 使用clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        // 这里完成对基本数据类型(属性) 和String 的克隆
        deep = super.clone();
        // 对引用类型的属性,进行单独处理
        // 先创建,转换子类类型
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();

        return deepProtoType;
    }
    /*
    * 问题: 这样不会递归拷贝么?
    * */
}

Clinet

package com.atguigu.prototype.deepclone;


public class Clinet {
    public static void main(String[] args) throws CloneNotSupportedException {
        DeepProtoType p = new DeepProtoType();
        p.name = "松江";
        p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");

        //方式1 完成深拷贝
        DeepProtoType p2 = (DeepProtoType) p.clone();

        System.out.println(p);
        System.out.println(p.name);
        System.out.println(p.deepCloneableTarget);
        System.out.println(p2);
        System.out.println(p2.name);
        System.out.println(p2.deepCloneableTarget);
        /*
        com.atguigu.prototype.deepclone.DeepProtoType@1540e19d
        松江
        com.atguigu.prototype.deepclone.DeepCloneableTarget@677327b6
        com.atguigu.prototype.deepclone.DeepProtoType@14ae5a5
        松江
        com.atguigu.prototype.deepclone.DeepCloneableTarget@7f31245a

        Process finished with exit code 0

        * */
        /*
        * todo 这种方式 就是可以 实现深拷贝
        * 说白了就是,在里面 提取出来属性对象, 单独进行拷贝
        * */
    }
}

第二种

DeepProtoType

package com.atguigu.prototype.deepclone;

import java.io.*;


public class DeepProtoType implements Serializable,Cloneable {
    public String name; // String 属性
    public DeepCloneableTarget deepCloneableTarget; // 引用类型属性

    public DeepProtoType() {
        super();
    }

    // 深拷贝 -- 方式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);
            // ois就读到了原来序列化出去的这个对象
            DeepProtoType copyObj = (DeepProtoType)ois.readObject();
            // 我用序列化这个特点,把你关联的引用的输出出去,读回来后就相当云拷贝了
            return copyObj;
            // 我们这波操作就是充分利用我们的序列化和饭序列化,
            // 把当前对象以对象流的方式输出和读回来,就不用一个一个来搞了
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 关闭已经打开的流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }

        return null;
    }
}

DeepCloneableTarget

package com.atguigu.prototype.deepclone;

import java.io.Serializable;


public class DeepCloneableTarget implements Serializable,Cloneable {
    /*
     *
     * */
    private static final long serialVersionUID = 1L;

    private String cloneName;

    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    public DeepCloneableTarget() {
        super();
    }

    // 因为该类的属性都是String, 因此我们这里使用默认的clone方法完成即可
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

Clinet

package com.atguigu.prototype.deepclone;


public class Clinet {
    public static void main(String[] args) throws CloneNotSupportedException {
        DeepProtoType p = new DeepProtoType();
        p.name = "松江";
        p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");

        // 方式2 完成深拷贝
        DeepProtoType p2 = (DeepProtoType) p.deepClone();

        System.out.println(p);
        System.out.println(p.name);
        System.out.println(p.deepCloneableTarget);
        System.out.println(p2);
        System.out.println(p2.name);
        System.out.println(p2.deepCloneableTarget);
        /*
        com.atguigu.prototype.deepclone.DeepProtoType@330bedb4
        松江
        com.atguigu.prototype.deepclone.DeepCloneableTarget@2503dbd3
        com.atguigu.prototype.deepclone.DeepProtoType@4f3f5b24
        松江
        com.atguigu.prototype.deepclone.DeepCloneableTarget@15aeb7ab

        Process finished with exit code 0
        * */

        // 推荐第2中

    }
}

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

  1. 创建新的对象比较复杂的时候,可以利用原型模式简化对象的创建过程,同时也能够提高效率
  2. 不用重新初始化对象,而是动态地获得对象运行时的状态
  3. 如果原始对象发生变化(增加或者减少属性),其他克隆对象的也会发生相应的编号,无需修改代码
  4. 在实现深克隆的时候可能需要比较复杂的代码
  5. 缺点: 需要为每一个类配备一个克隆方法,这对全新的类来说,不是很难,但是对已经有的类进行改造的时候,需要修改其源码,这就违背了ocp开放封闭原则,这点要注意一下.

  • 原型模式

results matching ""

    No results matching ""