浅拷贝和深拷贝

浅拷贝(shadow copy)和深拷贝(deep copy)

在设计模式中的原型模式中需要用到浅拷贝和深拷贝

浅拷贝: 拷贝基本属性,对于引用类型只拷贝其引用
深拷贝: 不仅拷贝基本属性,对于引用类型中的基本类型也拷贝一份

实现clone步骤:
1.实现Cloneable接口
2.重写Object类型的clone方法

Cloneable接口:

public interface Cloneable {
}
浅拷贝
//Address.java
public class Address implements Cloneable{

    public Address(String addrName) {
        this.addrName = addrName;
    }

    private String addrName;

    public String getAddrName() {
        return addrName;
    }

    public void setAddrName(String addrName) {
        this.addrName = addrName;
    }


    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        return obj;
    }

    @Override
    public String toString() {
        return "Address{" +
                "addrName='" + addrName + '\'' +
                '}';
    }
}

//Horse.java
public class Horse implements Cloneable{

    private String name;
    private Date birthday;

    private Address address;

    public Horse(String name, Date birthday, Address address) {
        System.out.println("constructor invoked...");
        this.name = name;
        this.birthday = birthday;
        this.address = address;
    }


    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;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object sheep = super.clone();
        return sheep;
    }

    @Override
    public String toString() {
        return "Horse{" +
                "name='" + name + '\'' +
                ", birthday=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(birthday) +
                ", address=" + address +
                '}';
    }
}

测试:

@Test
public void cloneTest() throws CloneNotSupportedException, InterruptedException {
   Address address = new Address("上海");
   Horse horse = new Horse("来福", new Date(), address);
   System.out.println("horse:  "+horse);
   Horse cloneHorse = (Horse) horse.clone();
   System.out.println("clonehorse:  "+cloneHorse);
   Thread.sleep(10000);
   horse.setBirthday(new Date());
   address.setAddrName("上海乐业");
   horse.setName("来福-2");
   System.out.println("after change...");
   System.out.println("horse:  "+horse);
   System.out.println("clonehorse:  "+cloneHorse);
}

结果:

constructor invoked...
horse:  Horse{name='来福', birthday=2018-03-19 10:50:56, address=Address{addrName='上海'}}
clonehorse:  Horse{name='来福', birthday=2018-03-19 10:50:56, address=Address{addrName='上海'}}
after change...
horse:  Horse{name='来福-2', birthday=2018-03-19 10:51:06, address=Address{addrName='上海乐业'}}
clonehorse:  Horse{name='来福', birthday=2018-03-19 10:50:56, address=Address{addrName='上海乐业'}}
  • 可以发现使用clone方式创建对象,不会调用构造函数
  • 引用类型Address随着原对象改变而改变
  • 但是为什么Date类型没有改变

查看Date源码发现Date中的clone方法是实现的深拷贝:

//Date.java
public Object clone() {
       Date d = null;
       try {
           d = (Date)super.clone();
           if (cdate != null) {
               d.cdate = (BaseCalendar.Date) cdate.clone();
           }
       } catch (CloneNotSupportedException e) {} // Won't happen
       return d;
   }
深拷贝实现对象创建

1.对引用类型进行一次拷贝,只需要将Horse.javaclone方法换成

@Override
protected Object clone() throws CloneNotSupportedException {
    Horse horse = (Horse) super.clone();
    horse.address = (Address) this.address.clone();
    return horse;
}

测试案例不变,测试结果:

constructor invoked...
horse:  Horse{name='来福', birthday=2018-03-19 10:59:05, address=Address{addrName='上海'}}
clonehorse:  Horse{name='来福', birthday=2018-03-19 10:59:05, address=Address{addrName='上海'}}
after change...
horse:  Horse{name='来福-2', birthday=2018-03-19 10:59:15, address=Address{addrName='上海乐业'}}
clonehorse:  Horse{name='来福', birthday=2018-03-19 10:59:05, address=Address{addrName='上海'}}

可以看到clonehorseaddress属性没有随着horse改变而改变

2.使用流(Stream)实现深拷贝

注意:使用流来实现深拷贝的时候对象不用实现Cloneable接口,但对象必须实现Serializable接口

public class Address implements Serializable{

    public Address(String addrName) {
        this.addrName = addrName;
    }

    private String addrName;

    public String getAddrName() {
        return addrName;
    }

    public void setAddrName(String addrName) {
        this.addrName = addrName;
    }


    @Override
    public String toString() {
        return "Address{" +
                "addrName='" + addrName + '\'' +
                '}';
    }
}

//Horse.java
public class Horse implements Serializable{

    private String name;
    private Date birthday;

    private Address address;

    public Horse(String name, Date birthday, Address address) {
        System.out.println("constructor invoked...");
        this.name = name;
        this.birthday = birthday;
        this.address = address;
    }


    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;
    }


    @Override
    public String toString() {
        return "Horse{" +
                "name='" + name + '\'' +
                ", birthday=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(birthday) +
                ", address=" + address +
                '}';
    }
}

实现深拷贝工具类:

public class HorseCloneObject {

    public static <T>T clone(T object){
        T cloneObj = null;
        try {

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);

            ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            cloneObj = (T) ois.readObject();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return cloneObj;
    }
}

测试

@Test
public void cloneTest() throws InterruptedException {
    Address address = new Address("上海");
    Horse horse = new Horse("来福", new Date(), address);
    System.out.println("horse:  "+horse);
    Horse cloneHorse = HorseCloneObject.clone(horse);
    System.out.println("clonehorse:  "+cloneHorse);
    Thread.sleep(10000);
    horse.setBirthday(new Date());
    address.setAddrName("上海乐业");
    horse.setName("来福-2");
    System.out.println("after change...");
    System.out.println("horse:  "+horse);
    System.out.println("clonehorse:  "+cloneHorse);
}

结果:

constructor invoked...
horse:  Horse{name='来福', birthday=2018-03-19 11:04:58, address=Address{addrName='上海'}}
clonehorse:  Horse{name='来福', birthday=2018-03-19 11:04:58, address=Address{addrName='上海'}}
after change...
horse:  Horse{name='来福-2', birthday=2018-03-19 11:05:08, address=Address{addrName='上海乐业'}}
clonehorse:  Horse{name='来福', birthday=2018-03-19 11:04:58, address=Address{addrName='上海'}}

可以看到同样实现了深拷贝对象的功能

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值