原型模式之深浅克隆

原型模式跟其他的创建型模式不同,它要做的是对特定的对象进行克隆。所谓克隆就是根据当前对象的特征,完全的复制一份出来。原型模式分为深拷贝和浅拷贝。不管是深拷贝和浅拷贝对于对象中的基本数据类型和String类型都会完全的复制,区别就是在复制对象中的其他引用类型时,浅拷贝只会复制对象中引用类型的地址,而不会完全的克隆一份。

浅拷贝

下面测试代码,User类中有Integer类型和String类型以及一个Father对象。User类对外提供的copy()方法使用了Object的clone()方法,就完成了对象的复制。需要注意的是,使用clone()方法的类需要实现Cloneable接口,该接口只是一个标记接口。最终的测试我们改变了克隆出来的对象的三个属性,原对象的Integer和String类型属性没有收到影响,而Father属性则收到了影响。这表明,克隆出来的对象并没有完全的复制,对于引用类型只是复制了其栈的引用。

package prototype_k;/*
 * @auther 顶风少年
 * @mail dfsn19970313@foxmail.com
 * @date 2020-01-15 17:49
 * @notify
 * @version 1.0
 */

public class User implements Cloneable {
    private String name;
    private Integer age;
    private Father father;

    public User(String name, Integer age, Father father) {
        this.name = name;
        this.age = age;
        this.father = father;
    }

    public User copy() throws Exception {
        return (User) this.clone();
    }

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

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

    public void setFather(Father father) {
        this.father = father;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public Father getFather() {
        return father;
    }
}
View Code
package prototype_k;/*
* @auther 顶风少年 
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:50
* @notify 
* @version 1.0
*/


public class Father {
    private String name;

    public Father(String name) {
        this.name = name;
    }

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

    public String getName() {
        return name;
    }
}
View Code
package prototype_k;/*
 * @auther 顶风少年
 * @mail dfsn19970313@foxmail.com
 * @date 2020-01-15 17:49
 * @notify
 * @version 1.0
 */

public class Main {
    public static void main(String[] args) throws Exception {
        User user = new User("张三", 1, new Father("张爸爸"));
        User cloneUser = user.copy();
        System.out.println(user == cloneUser);//false
        cloneUser.setName("李四");
        cloneUser.setAge(2);
        Father father = cloneUser.getFather();
        father.setName("李爸爸");

        System.out.println(user.getName());//张三
        System.out.println(user.getAge());//1
        System.out.println(user.getFather().getName());//李爸爸
    }
}
View Code

深拷贝

而深度拷贝需要使用对象序列化和反序列化,这个过程叫做冷冻和解冻。很好明白的,当一个对象被读取到了流里,那么流里的对象已经不是对象了,只是二进制数据,表明完全和原有的对象切断了联系。最后解冻则是一个完完全全的新的对象。需要注意的是被序列化的对象必须实现Serializable标记接口,对象内的其他引用对象也需要实现。

package prototype_k;/*
 * @auther 顶风少年
 * @mail dfsn19970313@foxmail.com
 * @date 2020-01-15 17:49
 * @notify
 * @version 1.0
 */

import java.io.*;

public class User2 implements Serializable{
    private String name;
    private Integer age;
    private Father father;

    public User2(String name, Integer age, Father father) {
        this.name = name;
        this.age = age;
        this.father = father;
    }

    public User2 copy() throws Exception {
        ByteArrayOutputStream byteInputStream = new ByteArrayOutputStream();
        ObjectOutputStream outputStream = new ObjectOutputStream(byteInputStream);
        outputStream.writeObject(this);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteInputStream.toByteArray());
        ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);
        Object object = inputStream.readObject();


        return (User2) object;
    }

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

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

    public void setFather(Father father) {
        this.father = father;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public Father getFather() {
        return father;
    }
}
View Code
package prototype_k;/*
* @auther 顶风少年 
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:50
* @notify 
* @version 1.0
*/

import java.io.Serializable;

public class Father implements Serializable {
    private String name;

    public Father(String name) {
        this.name = name;
    }

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

    public String getName() {
        return name;
    }
}
View Code
package prototype_k;/*
* @auther 顶风少年 
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 18:46
* @notify 
* @version 1.0
*/
public class Main2 {
    public static void main(String[] args)throws Exception {
        User2 user = new User2("张三", 1, new Father("张爸爸"));
        User2 cloneUser = user.copy();
        System.out.println(user == cloneUser);
        cloneUser.setName("李四");
        cloneUser.setAge(2);
        Father father = cloneUser.getFather();
        father.setName("李爸爸");

        System.out.println(user.getName());
        System.out.println(user.getAge());
        System.out.println(user.getFather().getName());
    }


}
View Code
posted @ 2020-01-15 19:19  顶风少年  阅读(357)  评论(0编辑  收藏  举报
返回顶部