在Java中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是对象复制时的两种主要策略。它们的主要区别在于如何处理对象中的引用类型字段。
浅拷贝(Shallow Copy)
浅拷贝只是复制对象的引用,而不是实际的对象。如果对象包含对另一个对象的引用,那么浅拷贝将只复制该引用,而不是引用的对象。因此,原始对象和复制对象将引用相同的对象。
原理分析
- 对于基本数据类型(byte, short, int, long, float, double, char, boolean),浅拷贝会直接复制值。
- 对于引用数据类型(类、接口、数组等),浅拷贝会复制引用,而不是引用的对象。
代码示例
public class ShallowCopyExample {
private int value;
private Object ref;
// 构造函数、getter和setter等省略
@Override
public ShallowCopyExample clone() {
try {
return (ShallowCopyExample) super.clone(); // 使用Object类的clone方法进行浅拷贝
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
ShallowCopyExample original = new ShallowCopyExample();
original.setValue(10);
original.setRef(new Object());
ShallowCopyExample copied = original.clone();
// 修改原始对象的引用对象
original.getRef().notify(); // 假设Object类有一个notify方法(实际没有,仅为示例)
// 复制对象也会受到影响,因为它们引用的是同一个对象
// 这里只是一个假设的示例,因为Object类没有notify方法
}
}
深拷贝(Deep Copy)
深拷贝会复制对象及其引用的对象,以及那些对象的引用对象,依此类推,直到没有引用为止。这意味着原始对象和复制对象是完全独立的,对其中一个的修改不会影响另一个。
原理分析
- 对于基本数据类型,深拷贝会直接复制值。
- 对于引用数据类型,深拷贝会递归地复制对象及其引用的所有对象。
代码示例
由于Java没有直接提供深拷贝的方法,我们通常需要手动实现或使用序列化(如果对象实现了Serializable
接口)或其他库(如Apache Commons Lang的SerializationUtils
)。
以下是一个使用序列化和反序列化实现深拷贝的示例:
下滑查看解决方法
import java.io.*;
public class DeepCopyExample implements Serializable {
private int value;
private Object ref;
// 构造函数、getter和setter等省略
public DeepCopyExample deepCopy() {
try {
// 写入对象到字节数组输出流(即序列化)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 从字节数组输入流读取对象(即反序列化)
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (DeepCopyExample) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
DeepCopyExample original = new DeepCopyExample();
original.setValue(10);
original.setRef(new Object());
DeepCopyExample copied = original.deepCopy();
// 修改原始对象的引用对象不会影响复制对象
// 因为它们是完全独立的对象
}
}
注意:使用序列化进行深拷贝时,必须确保对象及其所有引用的对象都实现了Serializable
接口,并且没有使用任何不支持序列化的字段(如瞬态字段)。