在Java中,深拷贝和浅拷贝的概念主要用于描述对象及其内部引用类型数据的复制方式。以下是Java中深拷贝和浅拷贝的详细总结,包括定义、实现方式及示例代码。
浅拷贝(Shallow Copy)
浅拷贝是指在创建新对象时,对于非引用类型的成员变量会直接复制其值,而对于引用类型的成员变量,只是复制了其引用,即新对象的引用类型成员变量指向的是原有对象的引用类型成员变量所指向的对象。
实现方式
使用Object.clone()
Java中的Object类提供了一个clone()方法,但它是受保护的,需要在子类中重写此方法,并声明为public。但是,clone()仅能实现浅拷贝。
如果对象的成员变量中有引用类型,那么这些引用类型的数据会被共享。
示例代码:
public class Person implements Cloneable {
private String name;
private List<String> hobbies;
// 构造函数、getters和setters省略...
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) {
try {
Person person1 = new Person("John");
person1.getHobbies().add("Reading");
Person person2 = (Person) person1.clone();
// 修改person2的hobbies,person1的hobbies也会被修改
person2.getHobbies().add("Swimming");
System.out.println(person1.getHobbies()); // 输出:[Reading, Swimming]
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
深拷贝(Deep Copy)
深拷贝是指在创建新对象时,对于非引用类型的成员变量会直接复制其值,而对于引用类型的成员变量,会递归地复制这些引用类型成员变量所指向的对象,从而创建一个全新的对象。
实现方式
序列化和反序列化
适用于实现了Serializable接口的对象。通过将对象转换成字节流再重新读取,可以实现深拷贝。
这种方式能够保证所有的成员变量都被复制,包括引用类型。
import java.io.*;
public class DeepCopyViaSerialization {
public static <T extends Serializable> T deepCopy(T obj) {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
bais = new ByteArrayInputStream(baos.toByteArray());
ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
try {
if (baos != null) baos.close();
if (oos != null) oos.close();
if (bais != null) bais.close();
if (ois != null) ois.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person("John");
person1.getHobbies().add("Reading");
Person person2 = DeepCopyViaSerialization.deepCopy(person1);
// 修改person2的hobbies,person1的hobbies不会被修改
person2.getHobbies().add("Swimming");
System.out.println(person1.getHobbies()); // 输出:[Reading]
}
}
使用第三方库
如Apache Commons Lang的org.apache.commons.lang3.SerializationUtils,或者ModelMapper等,它们提供了简便的深拷贝功能。
总结
选择使用深拷贝还是浅拷贝,主要取决于你的具体需求。如果你希望新对象和原对象完全独立,那么应该使用深拷贝。如果你只是需要一个对象的“视图”,并且可以接受它们共享某些数据,那么浅拷贝就足够了。深拷贝虽然更安全,但是它可能涉及更多的资源消耗,特别是在处理大型或复杂对象时。