介绍
深拷贝和浅拷贝 都会在堆中建立新的对象,将原对象的非静态字段复制到该新对象;对于基本数据类型的字段,直接进行值的复制;对于引用类型的字段,二者的处理有所不同。
浅拷贝:引用类型字段 是直接复制的 原对象中对应字段指向的对象的地址值,即 拷贝对象和原对象的相应引用类型字段 指向的都是同一个对象。
深拷贝:不同于 浅拷贝 直接复制对象地址值,深拷贝会将堆中的对象也拷贝一份,即 拷贝对象和原对象的相应引用类型字段 指向的是不同的对象。
实现
浅拷贝
Object 类提供的 clone() 方法可以非常简单地实现对象的浅拷贝。
示例如下:
Person 类实现了 Cloneable 接口,并重写了 clone() 方法。
clone() 方法的实现很简单,直接调用的是父类 Object 的 clone() 方法。
public class Address {
private String city;
public Address(String city) {
this.city = city;
}
// 省略getter、setter方法
}
public class Person implements Cloneable {
private Address address;
public Person(Address address) {
this.address = address;
}
// 省略getter、setter方法
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
}
测试:
Person person1 = new Person(new Address("Beijing"));
Person person2 = person1.clone();
System.out.println(person1 == person2); // false
System.out.println(person1.getAddress() == person2.getAddress()); // true
person1 == person2
为 false,说明拷贝得到的对象是新建立的;
person1.getAddress() == person2.getAddress()
为 true,说明拷贝对象与原对象引用的是同一个 Address 对象。
深拷贝
深拷贝有两种实现方式:重写克隆方法 和 序列化。
1.重写克隆方法
重写克隆方法,引用类型字段单独克隆。
示例如下:
Address 类也实现了 Cloneable 接口,因此可以对 Address 对象进行克隆;
Person 的 clone() 方法做了修改,address 字段单独设置,将原先的 address 对象拷贝一份后赋值给它。
public class Address implements Cloneable {
private String city;
public Address(String city) {
this.city = city;
}
// 省略getter、setter方法
@Override
public Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
}
public class Person implements Cloneable {
private Address address;
public Person(Address address) {
this.address = address;
}
// 省略getter、setter方法
// 重写克隆方法
@Override
public Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
// 引用类型字段单独克隆
person.setAddress(person.getAddress().clone());
return person;
}
}
测试:
Person person1 = new Person(new Address("Beijing"));
Person person2 = person1.clone();
System.out.println(person1 == person2); // false
System.out.println(person1.getAddress() == person2.getAddress()); // false
person1.getAddress() == person2.getAddress()
为 false,说明拷贝对象与原对象引用的 Address 对象是不同的了。
2.序列化
先讲原对象序列化,再反序列化成拷贝对象。
示例如下:
编写了深拷贝的工具类 CopyUtils,deepCopy 方法将对象序列化到字节流中,并从字节流中反序列化得到一个对象副本,即可实现深拷贝。
特别注意:Address 和 Person 需要实现序列化接口 Serializable。
// 深拷贝的工具类
public class CopyUtils {
public static Object deepCopy(Object obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
public class Address implements Serializable {
private String city;
public Address(String city) {
this.city = city;
}
// 省略getter、setter方法
}
public class Person implements Serializable {
private Address address;
public Person(Address address) {
this.address = address;
}
// 省略getter、setter方法
}
测试:
Person person1 = new Person(new Address("Beijing"));
Person person2 = (Person) CopyUtils.deepCopy(person1);
System.out.println(person1 == person2); // false
System.out.println(person1.getAddress() == person2.getAddress()); // false
person1.getAddress() == person2.getAddress()
为 false,说明拷贝对象与原对象引用的 Address 对象是不同的。
如果有帮助的话,可以点个赞支持一下嘛
🙏