深浅拷贝
深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 是两种不同的对象复制方式,主要区别在于它们如何处理对象内部的引用类型字段。
一、浅拷贝(Shallow Copy)
浅拷贝是指创建一个新对象,然后将原对象的字段值复制到新对象中。对于基本数据类型,直接复制值;对于引用类型,复制的是引用(即内存地址),而不是引用指向的对象本身。
特点
- 新对象和原对象共享引用类型的字段。
- 修改其中一个对象的引用类型字段,会影响另一个对象。
- 实现方式:
1. 使用 clone() 方法(需实现 Cloneable 接口)。
2. 手动复制字段。 - 示例
class Address {
String city;
Address(String city) {
this.city = city;
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("Beijing");
Person person1 = new Person("Alice", address);
Person person2 = (Person) person1.clone();
System.out.println(person1.address.city); // 输出: Beijing
System.out.println(person2.address.city); // 输出: Beijing
// 修改 person2 的 address
person2.address.city = "Shanghai";
// person1 的 address 也被修改
System.out.println(person1.address.city); // 输出: Shanghai
}
}
二、深拷贝(Deep Copy)
深拷贝是指创建一个新对象,并递归地复制原对象的所有字段,包括引用类型字段指向的对象。新对象和原对象完全独立,修改其中一个对象不会影响另一个对象。
特点
- 新对象和原对象不共享任何引用类型的字段。
- 修改其中一个对象的引用类型字段,不会影响另一个对象。
- 实现方式:
- 手动递归复制所有字段。
- 使用序列化(Serialization)和反序列化(Deserialization)。
- 使用第三方库(如 Apache Commons Lang 的 SerializationUtils)。
- 示例
import java.io.*;
class Address implements Serializable {
String city;
Address(String city) {
this.city = city;
}
}
class Person implements Serializable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 深拷贝(通过序列化实现)
public Person deepCopy() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
}
}
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Address address = new Address("Beijing");
Person person1 = new Person("Alice", address);
Person person2 = person1.deepCopy();
System.out.println(person1.address.city); // 输出: Beijing
System.out.println(person2.address.city); // 输出: Beijing
// 修改 person2 的 address
person2.address.city = "Shanghai";
// person1 的 address 不受影响
System.out.println(person1.address.city); // 输出: Beijing
}
}
三、如果选择浅拷贝或者深拷贝
使用浅拷贝:
- 当对象的引用类型字段不需要独立复制时。
- 当对象结构简单,且性能要求较高时。
使用深拷贝:
- 当对象的引用类型字段需要独立复制时。
- 当对象结构复杂,且需要完全独立的副本时。
深拷贝其他方式
手动递归复制:
- 对于每个引用类型字段,手动创建新对象并复制数据。
使用第三方库:
- 如 Apache Commons Lang 的 SerializationUtils.clone():
Person person2 = SerializationUtils.clone(person1);
总结
- 浅拷贝:复制引用,共享对象,适合简单场景。
- 深拷贝:复制对象,完全独立,适合复杂场景。