深拷贝与浅拷贝
在Java中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两种复制对象的方法,它们在处理对象及其引用类型字段时有着不同的行为。下面简述两者的区别和如何使用深拷贝复制对象。
浅拷贝
浅拷贝是创建一个新对象,这个新对象是对原对象的字段逐个拷贝。如果原对象的某个字段是一个引用类型(例如指向一个对象的引用),浅拷贝只会复制这个引用,而不会复制引用的实际对象。这样,新对象和原对象将共享相同的引用类型字段。
class Address {
String city;
String street;
Address(String city, String street) {
this.city = city;
this.street = street;
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 浅拷贝
}
}
在上述代码中,Person
类实现了 Cloneable
接口,clone
方法调用了 super.clone()
,这将执行浅拷贝。新 Person
对象和原对象将共享相同的 Address
对象引用。
深拷贝
深拷贝不仅创建一个新对象,还递归地复制所有引用类型的字段对象。这样,新对象和原对象完全独立,它们之间没有共享的引用。
class Address implements Cloneable {
String city;
String street;
Address(String city, String street) {
this.city = city;
this.street = street;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person clonedPerson = (Person) super.clone();
clonedPerson.address = (Address) address.clone(); // 深拷贝地址
return clonedPerson;
}
}
在上述代码中,Person
类的 clone
方法不仅克隆自身,还克隆其引用类型字段 Address
,实现了深拷贝。
常见的深拷贝方法
除了手动实现 clone
方法外,还有其他几种实现深拷贝的方法:
1. 使用构造函数
通过创建一个新的构造函数来复制对象的所有字段。这种方法不需要实现 Cloneable
接口,但需要手动编写构造函数。
class Address {
String city;
String street;
Address(String city, String street) {
this.city = city;
this.street = street;
}
// 深拷贝构造函数
Address(Address address) {
this.city = address.city;
this.street = address.street;
}
}
class Person {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 深拷贝构造函数
Person(Person person) {
this.name = person.name;
this.address = new Address(person.address);
}
}
2. 使用 JSON 序列化和反序列化
通过将对象转换为 JSON 字符串,然后再将其解析为对象,可以实现深拷贝。需要使用第三方库如 Gson 或 Jackson。
import com.google.gson.Gson;
class Address {
String city;
String street;
Address(String city, String street) {
this.city = city;
this.street = street;
}
}
class Person {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
}
public class Main {
public static void main(String[] args) {
Gson gson = new Gson();
Address address = new Address("New York", "5th Avenue");
Person person1 = new Person("John", address);
// 序列化为 JSON 字符串
String json = gson.toJson(person1);
// 反序列化为新对象
Person person2 = gson.fromJson(json, Person.class);
System.out.println(person1.address == person2.address); // false
}
}
3. 使用 Apache Commons Lang 的 SerializationUtils.clone(推荐)
这个方法非常简便,只不过需要确保所有参与深拷贝的类都实现 Serializable
接口。
import org.apache.commons.lang3.SerializationUtils;
import java.io.Serializable;
class Address implements Serializable {
String city;
String street;
Address(String city, String street) {
this.city = city;
this.street = street;
}
}
class Person implements Serializable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
}
public class Main {
public static void main(String[] args) {
Address address = new Address("New York", "5th Avenue");
Person person1 = new Person("John", address);
Person person2 = SerializationUtils.clone(person1);
System.out.println(person1.address == person2.address); // false
}
}
总结
在Java中,深拷贝和浅拷贝是两种不同的对象复制方式。浅拷贝只复制对象的引用,而深拷贝则递归复制所有引用类型的字段。选择适当的方法来实现深拷贝取决于具体的需求和上下文。以上几种方法各有优缺点,可以根据实际情况选择使用。