浅克隆与深克隆

1、浅克隆

1.1、什么是浅克隆?

        被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然

        指向原来的对象(克隆对象与原型对象共享引用数据类型变量)。

        如下图所示:

                

1.2、浅克隆代码实现

         类实现接口 Cloneable,表示该类的对象是可以克隆的

         示例代码1:

public class ConcretePrototype implements Cloneable {

    public ConcretePrototype() {
        System.out.println("具体的对象创建完成!");
    }

    @Override
    protected ConcretePrototype clone() throws CloneNotSupportedException {
        System.out.println("具体的对象复制成功!");
        return (ConcretePrototype)super.clone();
    }
}

      测试

@Test
    public void test01() throws CloneNotSupportedException {
        ConcretePrototype c1 = new ConcretePrototype();
        ConcretePrototype c2 = c1.clone();

        System.out.println("对象c1和c2是同一个对象?" + (c1 == c2));
    }

      打印结果:

             对象c1和c2是同一个对象?true

      示例代码2:

            在 类 ConcretePrototype 中添加一个引用类型的属性Person,如下所示:

public class ConcretePrototype implements Cloneable {

    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    void show(){
        System.out.println("嫌疑人姓名: " +person.getName());
    }

    public ConcretePrototype() {
        System.out.println("具体的对象创建完成!");
    }

    @Override
    protected ConcretePrototype clone() throws CloneNotSupportedException {
        System.out.println("具体的对象复制成功!");
        return (ConcretePrototype)super.clone();
    }

}

public class Person {

    private String name;

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

      测试:

@Test
    public void test02() throws CloneNotSupportedException {
        ConcretePrototype c1 = new ConcretePrototype();
        Person p1 = new Person();
        c1.setPerson(p1);

        //复制c1
        ConcretePrototype c2 = c1.clone();
        //获取复制对象c2中的Person对象
        Person p2 = c2.getPerson();
        p2.setName("慕容复");

        //判断p1与p2是否是同一对象
        System.out.println("p1和p2是同一个对象?" + (p1 == p2));

        c1.show();
        c2.show();
    }

     打印结果:

            p1和p2是同一个对象?true
            嫌疑人姓名:慕容复
            嫌疑人姓名:慕容复

     p1与p2是同一对象,这是浅克隆的效果,也就是对具体原型类中的引用数据类型的属性进行

     引用的复制

2、深克隆

2.1、什么是深克隆

         除去那些引用其他对象的变量,被复制对象的所有变量都含有与原来的对象相同的值。那些

         引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言

          之,深复制把要复制的对象所引用的对象都复制了一遍。如下图所示:

                

2.2、深克隆代码实现

         对于上边浅克隆示例2中的代码,如果有需求场景中不允许共享同一对象,那么就需要使用

         “深拷贝”,如果想要进行深拷贝需要使用到对象序列化流 (对象序列化之后,再进行反序列化

          获取到的是不同对象)。代码如下

@Test
    public void test03() throws Exception {

        ConcretePrototype c1 = new ConcretePrototype();
        Person p1 = new Person("峰哥");
        c1.setPerson(p1);

        //创建对象序列化输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c.txt"));

        //将c1对象写到文件中
        oos.writeObject(c1);
        oos.close();

        //创建对象序列化输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c.txt"));

        //读取对象
        ConcretePrototype c2 = (ConcretePrototype) ois.readObject();
        Person p2 = c2.getPerson();
        p2.setName("凡哥");

        //判断p1与p2是否是同一个对象
        System.out.println("p1和p2是同一个对象?" + (p1 == p2));

        c1.show();
        c2.show();
    }

3、总结

     1)Java中的Object类中提供了 `clone()` 方法来实现“浅克隆”。需要注意的是要想实现克隆

           的Java类必须实现一个标识接口 Cloneable ,来表示这个Java类支持被复制。

     2)其实现在不推荐大家用Cloneable接口,实现比较麻烦,现在借助Apache Commons或

          者springframework可以直接实现:
              (1)浅克隆:BeanUtils.cloneBean(Object obj);

                                      BeanUtils.copyProperties(S,T);
              (2)深克隆:SerializationUtils.clone(T object);
          BeanUtils是利用反射原理获得所有类可见的属性和方法,然后复制到target类。
          SerializationUtils.clone()就是使用我们的前面讲的序列化实现深克隆,当然你要把要克隆

          的类实现Serialization接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值