在 Java 中,深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 是两种常见的对象复制方式。它们的主要区别在于是否复制对象的引用类型字段。
1. 浅拷贝
定义
浅拷贝只复制对象本身,而不复制对象内部的引用类型字段。也就是说,浅拷贝后,原对象和新对象共享引用类型的字段。
实现方式
- 使用
clone()
方法:- 实现
Cloneable
接口。 - 重写
clone()
方法。
- 实现
示例代码
class Person implements Cloneable {
String name;
Address address; // 引用类型
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 默认是浅拷贝
}
}
class Address {
String city;
public Address(String city) {
this.city = city;
}
}
public class ShallowCopyExample {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("New York");
Person person1 = new Person("Alice", address);
// 浅拷贝
Person person2 = (Person) person1.clone();
// 修改 person2 的引用字段
person2.address.city = "Los Angeles";
System.out.println(person1.address.city); // 输出 Los Angeles
System.out.println(person2.address.city); // 输出 Los Angeles
}
}
结果分析
person1
和person2
共享同一个Address
对象。- 修改
person2.address.city
后,person1.address.city
也发生了变化。
2. 深拷贝
定义
深拷贝不仅复制对象本身,还递归地复制对象内部的所有引用类型字段。也就是说,深拷贝后,原对象和新对象完全独立。
实现方式
- 手动实现深拷贝:
- 遍历对象的所有字段,并逐一复制。
- 使用序列化:
- 将对象序列化为字节流,再反序列化为新对象。
方法 1:手动实现深拷贝
class Person implements Cloneable {
String name;
Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 深拷贝
Person cloned = (Person) super.clone();
cloned.address = new Address(this.address.city); // 复制引用字段
return cloned;
}
}
class Address {
String city;
public Address(String city) {
this.city = city;
}
}
public class DeepCopyExample {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("New York");
Person person1 = new Person("Alice", address);
// 深拷贝
Person person2 = (Person) person1.clone();
// 修改 person2 的引用字段
person2.address.city = "Los Angeles";
System.out.println(person1.address.city); // 输出 New York
System.out.println(person2.address.city); // 输出 Los Angeles
}
}
结果分析
person1
和person2
的Address
字段是独立的对象。- 修改
person2.address.city
不会影响person1.address.city
。
方法 2:使用序列化实现深拷贝
通过序列化和反序列化实现深拷贝,适用于复杂对象结构。
import java.io.*;
class Person implements Serializable {
String name;
Address address;
public 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();
}
}
class Address implements Serializable {
String city;
public Address(String city) {
this.city = city;
}
}
public class DeepCopyWithSerialization {
public static void main(String[] args) throws Exception {
Address address = new Address("New York");
Person person1 = new Person("Alice", address);
// 深拷贝
Person person2 = person1.deepCopy();
// 修改 person2 的引用字段
person2.address.city = "Los Angeles";
System.out.println(person1.address.city); // 输出 New York
System.out.println(person2.address.city); // 输出 Los Angeles
}
}
优点
- 自动处理复杂对象结构。
- 不需要手动编写深拷贝逻辑。
缺点
- 性能较低(涉及序列化和反序列化)。
- 被拷贝的类及其所有字段必须实现
Serializable
接口。
3. 浅拷贝与深拷贝的区别
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
复制内容 | 只复制对象本身,引用类型字段共享 | 递归复制对象及其所有引用类型字段 |
性能 | 更快 | 较慢(尤其是复杂对象结构) |
适用场景 | 对象的引用字段不需要独立时 | 对象的引用字段需要完全独立时 |
实现难度 | 简单(直接调用 clone() 或构造函数即可) | 较复杂(需手动或通过序列化实现) |
4. 总结
- 浅拷贝:
- 使用
clone()
方法实现。 - 原对象和新对象共享引用字段。
- 使用
- 深拷贝:
- 手动实现或通过序列化实现。
- 原对象和新对象完全独立。
- 选择依据:
- 如果对象的引用字段不需要独立,使用浅拷贝。
- 如果需要完全独立的对象,使用深拷贝。