原型模式的深浅复制和序列化

来源:互联网 发布:淘宝退款会影响信誉吗? 编辑:程序博客网 时间:2024/06/08 05:53

这是java的Object直接有方法的设计模式,面向对象的23种设计模式点这里。我们要做的只是实现Cloneable接口,这个接口的目的只是告诉jvm这个类的对象可以clone。同样的还有Serializable接口,今天说的跟它也有关系。

下面回到题目,复制和clone相信大家都知道。就是弄个一模一样的,而那个模子就叫原型。那么什么是深复制和浅复制呢?这和对象实现有关系,对象里的属性有基本类型和引用类型。一种复制是把基本类型复制,引用类型直接拿过来用。可以看出就复制一层就行了,所以叫浅复制。而深复制是把所有引用往下继续复制,直到全部属性是基本类型(对象属性最终存在计算机里是基本类型)。

那么Object的clone方法得到的是深复制还是浅复制呢。很遗憾是浅复制,为啥不是是深复制呢。因为浅复制简单,深复制还要考虑循环引用。先来看下浅复制

public class Prototype {    static class Student implements Cloneable{//这里为了简单,直接public,实际中不推荐        public int id = 12345;        public String name = "小明";        public Address address = new Address();        @Override        public Student clone() throws CloneNotSupportedException {            Student clone = (Student) super.clone();//            clone.address = address.clone();            return clone;        }    }    static class Address implements Cloneable{        public String name = "西湖";//        @Override//        public Address clone() throws CloneNotSupportedException {//            return (Address) super.clone();//        }    }    public static void main(String[] args) throws Exception {        Student student = new Student();        Student clone = student.clone();        clone.id = 54321;        clone.name = "小花";        clone.address.name = "瘦西湖";        System.out.println(student.id);        System.out.println(student.name);        System.out.println(student.address.name);    }}输出结果为:12345小明瘦西湖

可以看出clone.address == student.address,是引用复制。细心的可能发现了student.name != clone.name,这是因为这里String类似与基本类型,具体可以看一下第一个的String例子。

那么怎么深度复制呢,只要使用上面注释掉的代码就可以了。输出结果为:

12345小明西湖

可以看出每个对象都得重写clone方法,所以引出了开头说的Serializable接口。这个是序列化接口,也叫串行化。串行我们知道就是把所有东西一条线上排好,听着就像流。其实序列化的目的就是为了传送对象,就是根据一个对象,在另一个地方生成一样的对象,这不就是我们要的复制吗。程序如下:

public class Prototype {    static class Student implements Serializable {//这里为了简单,直接public,实际中不推荐        private static final long serialVersionUID = 6977402643848374753L;        //因为实际应用中类是会改动的,UID用来判断类版本,默认为1L;        public int id = 12345;        public String name = "小明";        public Address address = new Address();    }    static class Address implements Serializable {        public String name = "西湖";//        public Student student;    }    public static <T extends Serializable> T clone(T obj) throws Exception {        T cloneObj;        //写入字节流        ByteArrayOutputStream out = new ByteArrayOutputStream();        ObjectOutputStream obs = new ObjectOutputStream(out);        obs.writeObject(obj);        obs.close();        //分配内存,写入原始对象,生成新对象        ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());        ObjectInputStream ois = new ObjectInputStream(ios);        //返回生成的新对象        cloneObj = (T) ois.readObject();        ois.close();        return cloneObj;    }    public static void main(String[] args) throws Exception {        Student student = new Student();        Student clone = clone(student);//        student.address.student = student;        clone.address.name = "瘦西湖";        System.out.println(student.address.name);    }}

输出结果为: 西湖。可以看出直接是深复制,那么是不是循环引用也不用管了。我们同样把注释的可用,程序没有死循环,完美运行。当然序列化有个缺点就是效率低。

原创粉丝点击