参考文章:http://blog.csdn.net/XIAXIA__/article/details/41652057
解决问题:深拷贝、浅拷贝 和普通的对象赋值有什么区别?
对象复制
例如:Person p2 = p1;实质就是对象地址复制。把p1地址赋值给p2。此时二者同时指向一块堆内存,所以改变p1的属性值之后,p2所对应的属性值也会跟着变化。
例如有一个如下所示的Person类:
1 packagetudou.javabasic.clone;2
3 classPerson {4 private intage;5 privateString name;6 privateAddress address;7
8 publicAddress getAddress() {9 returnaddress;10 }11
12 public voidsetAddress(Address address) {13 this.address =address;14 }15
16 public Person(intage, String name) {17 this.age =age;18 this.name =name;19 }20
21 public intgetAge() {22 returnage;23 }24
25 public void setAge(intage) {26 this.age =age;27 }28
29 publicString getName() {30 returnname;31 }32
33 public voidsetName(String name) {34 this.name =name;35 }36
37 @Override38 publicString toString() {39 return "Person{" +
40 "age=" + age +
41 ", name='" + name + '\'' +
42 '}';43 }44 }
Person
执行如下代码:
1 public classCloneTest {2 public static voidmain(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 }
CloneTest
输出结果为:
p2.name before:first
p2.name after:second
如果在改变p1的值之后不想改变p2的值,应该如何处理呢?这时候需要用到拷贝,拷贝用到的函数为object的clone()方法
深拷贝和浅拷贝
clone()方法:
创建一个新对象,然后将当前对象的非静态字段复制到该新对象,
如果字段是值类型的,那么对该字段执行复制;
如果该字段是引用类型的话,则复制引用但不复制引用的对象。(这个称为浅拷贝)
原始对象及其副本引用同一个对象。
这个也就是说:如果使用clone()方法,对于值类型直接复制,对于引用类型 则还是采用复制 引用地址的方式。
代码如下:
1 packagetudou.javabasic.clone;2
3 /**
4 * Created by tudou on 2017-02-22.5 * 浅拷贝6 */
7 public class ShallowCopyPerson implementsCloneable {8 private intage;9 privateString name;10 privateAddress address;11
12 public ShallowCopyPerson(intage, String name, Address address) {13 this.age =age;14 this.name =name;15 this.address =address;16 }17 publicObject clone() {18 try{19 return (ShallowCopyPerson)super.clone();20 } catch(Exception e) {21 e.printStackTrace();22 return null;23 }24 }25
26 publicAddress getAddress() {27 returnaddress;28 }29
30 public voidsetAddress(Address address) {31 this.address =address;32 }33
34 public intgetAge() {35 returnage;36 }37
38 public void setAge(intage) {39 this.age =age;40 }41
42 publicString getName() {43 returnname;44 }45
46 public voidsetName(String name) {47 this.name =name;48 }49
50
51 @Override52 publicString toString() {53 return "ShallowCopyPerson{" +
54 "age=" + age +
55 ", name='" + name + '\'' +
56 ", address=" + address +
57 '}';58 }59 }
ShallowCopyPerson
ShallowCopyPerson 类扩展Cloneable接口,重点关注的方法是clone()方法,这里只是简单使用:
1 publicObject 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 voidshallowCopyTest() {3 Address address = new Address("Henan", "zhoukou");4 ShallowCopyPerson shallowCopyPerson = newShallowCopyPerson(5 18,6 "tudou",7 address8 );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 }
shallowCopyTest
结果如下:
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 packagetudou.javabasic.clone;2
3 /**
4 * Created by tudou on 2017-02-22.5 * 深拷贝6 */
7 public class DeepCopyPerson implementsCloneable {8 private intage;9 privateString name;10 privateAddress address;11
12 public DeepCopyPerson(intage, String name, Address address) {13 this.age =age;14 this.name =name;15 this.address =address;16 }17 publicObject clone() {18 try{19 return (DeepCopyPerson)super.clone();20 } catch(Exception e) {21 e.printStackTrace();22 return null;23 }24 }25
26 publicAddress getAddress() {27 returnaddress;28 }29
30 public voidsetAddress(String province, String city) {31 address = newAddress(province,city);32 address.setCity(city);33 address.setProvince(province);34 }35
36 public intgetAge() {37 returnage;38 }39
40 public void setAge(intage) {41 this.age =age;42 }43
44 publicString getName() {45 returnname;46 }47
48 public voidsetName(String name) {49 this.name =name;50 }51
52
53 @Override54 publicString toString() {55 return "ShallowCopyPerson{" +
56 "age=" + age +
57 ", name='" + name + '\'' +
58 ", address=" + address +
59 '}';60 }61 }
DeepCopyPerson
运行下面代码:
1 //对象深拷贝
2 private static voiddeepCopyTest() {3 Address address = new Address("Henan", "zhoukou");4 DeepCopyPerson deepCopyPerson = newDeepCopyPerson(5 18,6 "tudou",7 address8 );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 }
deepCopyTest
结果如下:
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'}}
可以看到这里值完全没有改变。这里实现的深拷贝只是简单的来实现效果,不做效率方面的考虑。
总结
对象赋值:把一个对象的地址复制给另一个对象,二者都指向堆栈中的地址。所以一个对象中的值变了,另一个也会变。
浅拷贝:对于基本类型,克隆对象和原对象相互独立,没有影响,对于引用类型,复制的还是地址值,所以一个改变了,另一个也会改变。
深拷贝:原对象和克隆对象相互独立,不受影响。