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

这是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);
    }
}

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值