浅拷贝(Shallow Copy)和深拷贝(Deep Copy)是两种用于复制对象的方法,它们的区别在于新对象如何处理原始对象中的引用类型数据成员。
浅拷贝
浅拷贝会创建一个新对象,这个新对象会复制原始对象的非静态字段。对于值类型的字段(如基本数据类型 int
, double
等),它会复制实际的值;而对于引用类型(如数组、对象等),它只复制引用而不复制引用所指向的对象。这意味着原始对象和新对象将共享这些引用类型的数据。
在Java中,可以通过调用 Object
类的 clone()
方法实现浅拷贝,但需要注意的是,只有当类实现了 Cloneable
接口时,clone()
方法才能正常工作,并且可能需要重写 clone()
方法来确保正确的行为。
public class ShallowCopyExample implements Cloneable {
private int value;
private Object referenceType;
// Constructor, getters and setters...
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 默认是浅拷贝
}
}
深拷贝
深拷贝不仅会创建一个新的对象,还会递归地复制所有被引用的对象。因此,原始对象和新对象及其内部的所有对象都是完全独立的,修改一个对象不会影响另一个对象。
要实现深拷贝,可以选择以下几种方式之一:
- 手动复制:在
clone()
方法中手动复制每个引用类型的字段。 - 使用序列化:如果对象及其包含的所有对象都实现了
Serializable
接口,那么可以使用序列化和反序列化来实现深拷贝。 - 使用第三方库:一些库如 Apache Commons Lang 提供了
SerializationUtils.clone()
方法来进行深拷贝。
下面是一个使用序列化进行深拷贝的例子:
import java.io.*;
public class DeepCopyExample implements Serializable {
private int value;
private Object referenceType;
// Constructor, getters and setters...
public DeepCopyExample deepCopy() throws IOException, ClassNotFoundException {
// 序列化到字节数组输出流
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos)) {
out.writeObject(this);
// 反序列化从字节数组输入流
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bis)) {
return (DeepCopyExample) in.readObject();
}
}
}
}
深拷贝比浅拷贝更耗费资源,因为它需要复制更多的数据。此外,深拷贝可能会遇到循环引用的问题,即两个或多个对象互相引用的情况,在这种情况下,简单的递归复制方法会导致无限循环。因此,实现深拷贝时通常需要特别处理这种情况。