233_尚学堂_高淇_java300集最全视频教程_【GOF23设计模式】_原型模式_prototype_浅复制_深复制_反序列化实现深复制

原型模式分为深复制和浅复制
浅复制:只是拷贝对象本身,不拷贝对象的属性,所以”浅“。复制后的对象自然在内存中位于不同的地址中,因为本质上是两个对象,所以内存中的地址自然不同。但是复制之后的对象的属性却与原对象的属性相同,也就是两个对象的属性在内存中位于同一地址,并没有拷贝出另一份。复制(或者说拷贝)的意思是生成了另外的对象,只是复制对象本身,说明生成了本质上别的对象,在内存中另一个地方,没有复制对象的属性,说明两个对象的属性在内存中同一地方。

深赋值:既复制了对象本身,也复制了对象的属性,也就是说复制后的对象的属性在内存中的另外的地址中,尽管另外的地址中的内容跟原对象的相同。

public class Sheep01 implements Cloneable{
    private Date date;
    private String name;
    private Date birthday;

    public Sheep01(){
    }
    public Sheep01(Date date, String name, Date birthday) {
        this.date = date;
        this.name = name;
        this.birthday = birthday;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep01 s = (Sheep01) super.clone();
        s.date = (Date) this.date.clone();  //对date这个属性进行了深复制
        //birthday这个属性并没有深复制
        return s;
    }

    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
public class Demo01 {
    public static void main(String[] args) throws CloneNotSupportedException {
        //正确示例
        Date date1 = new Date();
        Date date2 = new Date();
        Sheep01 s1 = new Sheep01(date1, "hah", date2);
        Sheep01 s2 = (Sheep01) s1.clone();
        date1.setTime(234234234234L);
        date2.setTime(3423424234243L);
        System.out.println(s1.getDate()+"====="+s2.getDate());
        System.out.println(s1.getBirthday()+"====="+s2.getBirthday());
    }
}
/*
结果:
s1:Sat Jun 04 09:03:54 CST 1977=====s2:Mon Jun 15 22:48:45 CST 2015
s1:Sun Jun 26 07:10:34 CST 2078=====s2:Sun Jun 26 07:10:34 CST 2078
*/

因为s2的date进行了深复制,所以s2的date跟s1的虽然开始时间值相同,但是是不同的对象,所以改变s1的date的时间之后,s2的date的时间并没有变化。
因为s2的birthday是浅赋值,s2的birthday与s1的birthday是同一个对象,所以改变了s1的birthday后s2的birthday自然会变化。
这里注意一个问题:

public class Demo01 {
    public static void main(String[] args) throws CloneNotSupportedException {
        //错误示例,set的时候,不能new新的对象
        Sheep01 s1 = new Sheep01(new Date(), "hah", new Date(1121212121L));
        Sheep01 s2 = (Sheep01) s1.clone();
        s1.setDate(new Date(333223223L));
        s1.setBirthday(new Date(45645454534L));
        System.out.println(s1.getDate()+"====="+s2.getDate());
        System.out.println(s1.getBirthday()+"====="+s2.getBirthday());
    }
}
/*
结果:
s1:Mon Jan 05 04:33:43 CST 1970=====s2:Mon Jun 15 22:52:23 CST 2015
s1:Sun Jun 13 15:17:34 CST 1971=====s2:Wed Jan 14 07:26:52 CST 1970
*/

这里s1在设置时间的时候,并不是改变原来的对象的时间值,而是让s1的date和birthday指向其他的对象,原来的对象没有变化,所以改了s1之后s2并不会变化,所以输出结果无论是深复制还是浅赋值,s1和s2的结果都是不同的。

通过反序列化实现深复制,不需要在clone方法中手动写深复制需要的代码。例程如下:

import java.io.Serializable;
import java.util.Date;

public class Sheep02 implements Cloneable, Serializable{
    private Date date;
    private String name;
    private Date birthday;

    public Sheep02(){
        // TODO Auto-generated constructor stub
    }
    public Sheep02(Date date, String name, Date birthday) {
        super();
        this.date = date;
        this.name = name;
        this.birthday = birthday;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        Sheep02 s = (Sheep02) super.clone();
        return s;
    }

    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

}

/**
 * 通过反序列化实现深复制,用到两种IO流
 * @author Hong
 *
 */
public class Demo02 {
    public static void main(String[] args) throws Exception {
        Date date = new Date();
        Sheep02 s = new Sheep02();
        s.setDate(date);
        System.out.println("s:  "+s.getDate());
        //os可以将对象转换成输出流,同时bao可以获得这个输出流,并且可以转化成字节数组
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);

        oos.writeObject(s);
        byte[] b = bao.toByteArray();

        //bai可以将字节数组转化成输入流,ois可以获得这个输入流,并且将输入流转化成对象
        ByteArrayInputStream bai = new ByteArrayInputStream(b);
        ObjectInputStream ois = new ObjectInputStream(bai);

        Sheep02 s2 = (Sheep02) ois.readObject();
        System.out.println("s2:  "+s2.getDate());

        date.setTime(23232323232L);

        System.out.println("s:  "+s.getDate() +"----s2:  "+s2.getDate());
    }
}

/**
运行结果:
s:  Thu Jun 18 21:01:56 CST 2015
s2:  Thu Jun 18 21:01:56 CST 2015
s:  Sun Sep 27 05:25:23 CST 1970----s2:  Thu Jun 18 21:01:56 CST 2015
**/

你可能感兴趣的:(尚学堂Java300集学习笔记)