深拷贝、浅拷贝 和普通的对象赋值的作用和区别
解决问题:深拷贝、浅拷贝 和普通的对象赋值有什么区别?
对象复制
例如: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 }
Person
执行如下代码:
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 }
CloneTest
输出结果为:
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
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 }
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 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 }
DeepCopyPerson
运行下面代码:
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 }
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'}}
可以看到这里值完全没有改变。这里实现的深拷贝只是简单的来实现效果,不做效率方面的考虑。
总结
对象赋值:把一个对象的地址复制给另一个对象,二者都指向堆栈中的地址。所以一个对象中的值变了,另一个也会变。
浅拷贝:对于基本类型,克隆对象和原对象相互独立,没有影响,对于引用类型,复制的还是地址值,所以一个改变了,另一个也会改变。
深拷贝:原对象和克隆对象相互独立,不受影响。