参考文章:http://blog.youkuaiyun.com/XIAXIA__/article/details/41652057
解决问题:深拷贝、浅拷贝 和普通的对象赋值有什么区别?
对象复制
例如:Person p2 = p1;实质就是对象地址复制。把p1地址赋值给p2。此时二者同时指向一块堆内存,所以改变p1的属性值之后,p2所对应的属性值也会跟着变化。
例如有一个如下所示的Person类:


1 package tudou.javabasic.clone; 2 3 class Person { 4 private int age; 5 private String name; 6 private Address address; 7 8 public Address getAddress() { 9 return address; 10 } 11 12 public void setAddress(Address address) { 13 this.address = address; 14 } 15 16 public Person(int age, String name) { 17 this.age = age; 18 this.name = name; 19 } 20 21 public int getAge() { 22 return age; 23 } 24 25 public void setAge(int age) { 26 this.age = age; 27 } 28 29 public String getName() { 30 return name; 31 } 32 33 public void setName(String name) { 34 this.name = name; 35 } 36 37 @Override 38 public String toString() { 39 return "Person{" + 40 "age=" + age + 41 ", name='" + name + '\'' + 42 '}'; 43 } 44 }
执行如下代码:


1 public class CloneTest { 2 public static void main(String[] args) { 3 Person p1 = new Person(1, "first"); 4 Person p2 = p1;//把p1的引用赋值给p2 5 System.out.println("p2.name before:"+p2.getName()); 6 p1.setName("second"); 7 System.out.println("p2.name after:"+p2.getName()); 8 } 9 }
输出结果为:
p2.name before:first
p2.name after:second
如果在改变p1的值之后不想改变p2的值,应该如何处理呢?这时候需要用到拷贝,拷贝用到的函数为object的clone()方法
深拷贝和浅拷贝
clone()方法:
创建一个新对象,然后将当前对象的非静态字段复制到该新对象,
如果字段是值类型的,那么对该字段执行复制;
如果该字段是引用类型的话,则复制引用但不复制引用的对象。(这个称为浅拷贝)
原始对象及其副本引用同一个对象。
这个也就是说:如果使用clone()方法,对于值类型直接复制,对于引用类型 则还是采用复制 引用地址的方式。
代码如下:


1 package tudou.javabasic.clone; 2 3 /** 4 * Created by tudou on 2017-02-22. 5 * 浅拷贝 6 */ 7 public class ShallowCopyPerson implements Cloneable { 8 private int age; 9 private String name; 10 private Address address; 11 12 public ShallowCopyPerson(int age, String name, Address address) { 13 this.age = age; 14 this.name = name; 15 this.address = address; 16 } 17 public Object clone() { 18 try { 19 return (ShallowCopyPerson)super.clone(); 20 } catch (Exception e) { 21 e.printStackTrace(); 22 return null; 23 } 24 } 25 26 public Address getAddress() { 27 return address; 28 } 29 30 public void setAddress(Address address) { 31 this.address = address; 32 } 33 34 public int getAge() { 35 return age; 36 } 37 38 public void setAge(int age) { 39 this.age = age; 40 } 41 42 public String getName() { 43 return name; 44 } 45 46 public void setName(String name) { 47 this.name = name; 48 } 49 50 51 @Override 52 public String toString() { 53 return "ShallowCopyPerson{" + 54 "age=" + age + 55 ", name='" + name + '\'' + 56 ", address=" + address + 57 '}'; 58 } 59 }
ShallowCopyPerson 类扩展Cloneable接口,重点关注的方法是clone()方法,这里只是简单使用:
1 public Object clone() { 2 try { 3 return (ShallowCopyPerson)super.clone(); 4 } catch (Exception e) { 5 e.printStackTrace(); 6 return null; 7 } 8 }
接下来使用ShallowCopyPerson 类,来观察下列代码的运行结果:


1 //对象浅拷贝 2 private static void shallowCopyTest() { 3 Address address = new Address("Henan", "zhoukou"); 4 ShallowCopyPerson shallowCopyPerson = new ShallowCopyPerson( 5 18, 6 "tudou", 7 address 8 ); 9 ShallowCopyPerson personClone = (ShallowCopyPerson) shallowCopyPerson.clone(); 10 System.out.println("personClone info before:" + personClone.toString()); 11 System.out.println("shallowCopyPerson info before:" + shallowCopyPerson.toString()); 12 //这里改变原 shallowCopyPerson的值 13 shallowCopyPerson.setName("new tudou"); 14 shallowCopyPerson.setAge(19); 15 //改变address的地址值 16 address.setCity("fj"); 17 address.setProvince("fz"); 18 shallowCopyPerson.setAddress(address); 19 System.out.println("personClone info after:" + personClone.toString()); 20 System.out.println("shallowCopyPerson info before:" + shallowCopyPerson.toString()); 21 }
结果如下:
1 ersonClone info before:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}} 2 shallowCopyPerson info before:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}} 3 personClone info after:ShallowCopyPerson{age=18, name='tudou', address=Address{province='fz', city='fj'}} 4 shallowCopyPerson info before:ShallowCopyPerson{age=19, name='new tudou', address=Address{province='fz', city='fj'}}
从结果可以看到:age和name字段 在原对象shallowCopyPerson的属性改变之后 personclone并未改变。但是,address中的字段province和city均有改变!这种方式属于浅拷贝,即clone()方法是浅拷贝。
如何使得address中的字段值也不改变呢?就需要用到深拷贝。


1 package tudou.javabasic.clone; 2 3 /** 4 * Created by tudou on 2017-02-22. 5 * 深拷贝 6 */ 7 public class DeepCopyPerson implements Cloneable { 8 private int age; 9 private String name; 10 private Address address; 11 12 public DeepCopyPerson(int age, String name, Address address) { 13 this.age = age; 14 this.name = name; 15 this.address = address; 16 } 17 public Object clone() { 18 try { 19 return (DeepCopyPerson)super.clone(); 20 } catch (Exception e) { 21 e.printStackTrace(); 22 return null; 23 } 24 } 25 26 public Address getAddress() { 27 return address; 28 } 29 30 public void setAddress(String province, String city) { 31 address = new Address(province,city); 32 address.setCity(city); 33 address.setProvince(province); 34 } 35 36 public int getAge() { 37 return age; 38 } 39 40 public void setAge(int age) { 41 this.age = age; 42 } 43 44 public String getName() { 45 return name; 46 } 47 48 public void setName(String name) { 49 this.name = name; 50 } 51 52 53 @Override 54 public String toString() { 55 return "ShallowCopyPerson{" + 56 "age=" + age + 57 ", name='" + name + '\'' + 58 ", address=" + address + 59 '}'; 60 } 61 }
运行下面代码:


1 //对象深拷贝 2 private static void deepCopyTest() { 3 Address address = new Address("Henan", "zhoukou"); 4 DeepCopyPerson deepCopyPerson = new DeepCopyPerson( 5 18, 6 "tudou", 7 address 8 ); 9 DeepCopyPerson personClone = (DeepCopyPerson) deepCopyPerson.clone(); 10 System.out.println("personClone info before:" + personClone.toString()); 11 //这里改变原 shallowCopyPerson的值 12 deepCopyPerson.setName("new tudou"); 13 deepCopyPerson.setAge(19); 14 //改变address的地址值 15 // address.setCity("zhengzhou"); 16 deepCopyPerson.setAddress("fj","fz"); 17 System.out.println("personClone info after:" + personClone.toString()); 18 }
结果如下:
personClone info before:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}}
personClone info after:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}}
可以看到这里值完全没有改变。这里实现的深拷贝只是简单的来实现效果,不做效率方面的考虑。
总结
对象赋值:把一个对象的地址复制给另一个对象,二者都指向堆栈中的地址。所以一个对象中的值变了,另一个也会变。
浅拷贝:对于基本类型,克隆对象和原对象相互独立,没有影响,对于引用类型,复制的还是地址值,所以一个改变了,另一个也会改变。
深拷贝:原对象和克隆对象相互独立,不受影响。