java浅克隆和深克隆的区别详细讲解

时间:2018-08-20
本文章向大家介绍java浅克隆和深克隆的区别详细讲解,需要的朋友可以参考一下

Java对象的克隆有深克隆和浅克隆之分。有这种区分的原因是Java中分为基本数据类型和引用数据类型,对于不同的数据类型在内存中的存储的区域是不同的。基本数据类型存储在栈中,引用数据类型存储在堆中。

什么是克隆

克隆就是依据已经有的数据,创造一份新的完全一样的数据拷贝。

浅克隆

实现克隆有多种方式,可以手工的new出一个新的对象,然后将原来的对象信息一个一个的set到新的对象中。还有就是使用clone方法。使用clone方法必须满足:

1、要实现浅克隆被克隆的类必须实现Cloneable接口

2未实现接口会跑出CloneNotSupportedException异常

示例

package com.winter.clone;

public class Customer implements Cloneable {

public int ID;

public int age;

public Address address;

public int getID() {

return ID;

}

public void setID(int iD) {

ID = iD;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public Address getAddress() {

return address;

}

public void setAddress(Address address) {

this.address = address;

}

public Customer(int iD, int age, Address address) {

super();

ID = iD;

this.age = age;

this.address = address;

}

@Override

public String toString() {

return "Customer [ID=" + ID + ", age=" + age + ", address=" + address

+ "]";

}

@Override

public Customer clone() throws CloneNotSupportedException {

return (Customer) super.clone();

}

public static void main(String[] args) throws CloneNotSupportedException {

Address address = new Address("CH", "SD", "QD");

Customer customer1 = new Customer(1, 23, address);

Customer customer2 = customer1.clone();

customer2.getAddress().setCity("JN");

customer2.setID(2);

System.out.println("改变customer2 id:2与address:JN");

System.out.println("customer1:" + customer1.toString());

System.out.println("customer2:" + customer2.toString());

}

}

class Address {

private String country;

private String province;

private String city;

public String getCountry() {

return country;

}

public void setCountry(String country) {

this.country = country;

}

public String getProvince() {

return province;

}

public void setProvince(String province) {

this.province = province;

}

public String getCity() {

return city;

}

public void setCity(String city) {

this.city = city;

}

@Override

public String toString() {

return "Address [country=" + country + ", province=" + province

+ ", city=" + city + "]";

}

public Address(String country, String province, String city) {

super();

this.country = country;

this.province = province;

this.city = city;

}

}

改变customer2 id:2与address:JN

customer1:Customer [ID=1, age=23, address=Address [country=CH, province=SD, city=JN]]

customer2:Customer [ID=2, age=23, address=Address [country=CH, province=SD, city=JN]]

上面分析得到,clone后新旧对象互不影响,customer2修改了id后没有影响到customer1,但是修改了customer2的address属性的city值为JN后,发现customer1的address值也发生了改变。这样就没有达到完全复制、相互之间完全没有影响的目的。这样就需要进行深克隆。

深克隆

定义被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。深克隆的是实现实际上是对对象的序列化和反序列化

深克隆的实现就是在引用类型所在的类实现Cloneable接口,并使用public访问修饰符重写clone方法。

示例一:

1.Address类实现Cloneable接口,重写clone方法;

@Override  

public Address clone() throws CloneNotSupportedException {  

    return (Address) super.clone();  

}

  1. 在Customer类的clone方法中调用Address类的clone方法。

@Override  

public Customer clone() throws CloneNotSupportedException {  

    Customer customer = (Customer) super.clone();  

    customer.address = address.clone();  

    return customer;  

}  

发现customer2无论如何修改,customer1都没有受到影响。

改变customer2 id:2与address:JN

customer1:Customer [ID=1, age=23, address=Address [country=CH, province=SD, city=QD]]

customer2:Customer [ID=2, age=23, address=Address [country=CH, province=SD, city=JN]]

实现深克隆的另一种方法就是使用序列化,将对象写入到流中,这样对象的内容就变成了字节流,也就不存在什么引用了。然后读取字节流反序列化为对象就完成了完全的复制操作了。

1被克隆类以及被克隆类的引用必须实现Serializable接口

2未实现接口会抛出NotSerializableException异常

示例二:

public static Object cloneObject(Object obj) throws IOException, ClassNotFoundException{  

    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  

    ObjectOutputStream out = new ObjectOutputStream(byteOut);  

    out.writeObject(obj);   

    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  

    ObjectInputStream in =new ObjectInputStream(byteIn);  

    return in.readObject();  

}  

改变customer2 id:2与address:JN

customer1:Customer [ID=1, age=23, address=Address [country=CH, province=SD, city=QD]]

customer2:Customer [ID=2, age=23, address=Address [country=CH, province=SD, city=JN]]

总结

1.浅克隆:只复制基本类型的数据,引用类型的数据只复制了引用的地址,引用的对象并没有复制,在新的对象中修改引用类型的数据会影响原对象中的引用。
2.深克隆:是在引用类型的类中也实现了clone,是clone的嵌套,复制后的对象与原对象之间完全不会影响。
3.使用序列化也能完成深复制的功能:对象序列化后写入流中,此时也就不存在引用什么的概念了,再从流中读取,生成新的对象,新对象和原对象之间也是完全互不影响的。