再说深拷贝和浅拷贝之前先讲一个概念,引用拷贝和对象拷贝
经常有人会把引用拷贝理解为浅拷贝
1 Dog dog1 = new Dog();
2 Dog dog2 = dog1;
这其实只是一个赋值操作,把dog1的值赋值给了dog2,他们指向的其实是同一个对象,这种情况属于引用拷贝,通常意义上的深拷贝和浅拷贝都指的是对象拷贝
深拷贝和浅拷贝的理解
浅拷贝:
原型对象和复制出来的新对象,他们的引用类型的属性如果地址值相同则是浅拷贝
浅拷贝需要实现Cloneable接口,Cloneable其实是个空接口,相当于一个标记(和Serializable接口一样),重写clone方法,里面调用父类的clone方法即可(调用的是Object的clone方法)。
1public class Dog implements Cloneable {
2
3 /**
4 * 年龄(基本类型)
5 */
6 private int age;
7
8 /**
9 * 主人(引用类型)
10 */
11 private DogOwner owner;
12
13 public Dog clone() throws CloneNotSupportedException {
14 return (Dog)super.clone();
15 }
16}
通过调用clone方法拷贝的对象你会发现是重新创建了一个对象,但是对象里面的引用类型的熟悉指向的还是同一个地址(dog1和dog2指向的地址不同,dog1和dog2中的dogOwner指向的地址相同)
1 Dog dog1 = new Dog();
2 dog1.setAge(5);
3 DogOwner dogOwner = new DogOwner();
4 dog1.setOwner(dogOwner);
5 Dog dog2 = (Dog) dog1.clone();
6 System.out.println("dog1是否等于dog2: "+(dog1 == dog2));
7 System.out.println("dog1中的owner是否等于dog2中的owner: "+(dog1.getOwner() == dog2.getOwner()));
深拷贝:
原型对象和复制出来的新对象,他们的所有属性的地址值都是不同的
深拷贝的实现方式有很多种,常见方式就是通过序列化和反序列化、转json字符串在转成对象(其实原理类似)
我们以序列化为例:首先Dog类和DogOwner类都实现Serializable接口,然后通过序列化和反序列化操作得到新的对象,我们会发现dog对象和里面的引用类型的属性指向的地址都不同,此时就是完成了深拷贝
1 Dog dog1 = new Dog();
2 dog1.setAge(5);
3 DogOwner dogOwner = new DogOwner();
4 dog1.setOwner(dogOwner);
5
6 //将对象序列化到二进制流
7 ByteArrayOutputStream bos = new ByteArrayOutputStream();
8 ObjectOutputStream oos = new ObjectOutputStream(bos);
9 oos.writeObject(dog1);
10
11 //从二进制流中读出产生的新对象
12 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
13 ObjectInputStream ois = new ObjectInputStream(bis);
14 Dog dog2 = (Dog)ois.readObject();
15
16 System.out.println("dog1是否等于dog2: " + (dog1 == dog2));
17 System.out.println("dog1中的owner是否等于dog2中的owner: " + (dog1.getOwner() == dog2.getOwner()));