在Java编程中,浅拷贝和深拷贝是对象复制的两种方式。它们的主要区别在于是否复制对象的引用对象。以下是对这两种拷贝方式的详细说明:
浅拷贝 (Shallow Copy)
浅拷贝是对象的字段逐位复制。也就是说,对于对象的非引用类型(基本数据类型)字段,会直接复制其值;对于对象的引用类型字段(如数组、对象等),只会复制引用,而不会复制实际对象。结果是,原对象和浅拷贝对象共享同一个引用对象。
浅拷贝的实现方式
- 使用
clone()
方法:
- 实现
Cloneable
接口,并重写clone()
方法。
class Person implements Cloneable {
String name;
int age;
Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Address {
String city;
String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("New York", "5th Avenue");
Person person1 = new Person("John", 30, address);
Person person2 = (Person) person1.clone();
System.out.println(person1.address == person2.address); // 输出 true
}
}
深拷贝 (Deep Copy)
深拷贝会创建一个新对象,并递归地复制所有引用类型的字段。也就是说,深拷贝会复制对象的所有子对象,确保原对象和复制对象之间没有共享的引用对象。
深拷贝的实现方式
- 通过重写
clone()
方法:
- 在
clone()
方法中手动拷贝所有引用对象。
class Person implements Cloneable {
String name;
int age;
Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) address.clone(); // 深拷贝Address
return cloned;
}
}
class Address implements Cloneable {
String city;
String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("New York", "5th Avenue");
Person person1 = new Person("John", 30, address);
Person person2 = (Person) person1.clone();
System.out.println(person1.address == person2.address); // 输出 false
}
}
- 通过序列化和反序列化实现深拷贝:
- 将对象序列化为字节流,再反序列化为新对象。这种方法需要对象和所有子对象实现
Serializable
接口。
import java.io.*;
class Person implements Serializable {
String name;
int age;
Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
}
class Address implements Serializable {
String city;
String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
}
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Address address = new Address("New York", "5th Avenue");
Person person1 = new Person("John", 30, address);
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(person1);
// 反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Person person2 = (Person) ois.readObject();
System.out.println(person1.address == person2.address); // 输出 false
}
}
总结
- 浅拷贝:复制对象的基本类型字段,对引用类型字段只复制引用,不复制实际对象。
- 深拷贝:复制对象的基本类型字段和引用类型字段,引用类型字段的实际对象也会被递归地复制。
选择使用哪种拷贝方式取决于具体需求和应用场景。在需要完全独立的副本时,使用深拷贝;在不需要完全独立的副本时,使用浅拷贝。