文章目录
- 基本概念
- 浅拷贝
- 深拷贝
-
- [重写 clone() 方法实现深拷贝](#重写 clone() 方法实现深拷贝)
- 使用序列化实现深拷贝
- 使用复制构造函数或工厂方法
基本概念
-
浅拷贝:创建一个新对象,然后将原对象的非静态字段(基本类型和引用类型)直接复制到新对象中。对于引用类型字段,复制的是引用地址,即新对象和原对象中的引用字段指向同一个实例。因此,修改其中一个对象的引用字段内容,会影响另一个对象。
-
深拷贝:创建一个新对象,并递归地复制原对象中所有引用类型字段所引用的对象,直到所有层次都被完全复制。新对象和原对象完全独立,修改一个不会影响另一个。
浅拷贝
&emap;默认的 super.clone() 执行的是浅拷贝,此时p1 和 p2 的 address 引用指向同一个 Address 对象,因此修改 p2 的地址会影响 p1
java
class Address {
String city;
Address(String city) { this.city = city; }
// getter/setter 省略
}
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(); // 浅拷贝
}
// getter/setter 省略
}
public class ShallowCopyDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr = new Address("北京");
Person p1 = new Person("张三", addr);
Person p2 = (Person) p1.clone();
System.out.println(p1.address.city); // 北京
System.out.println(p2.address.city); // 北京
// 修改 p2 的地址
p2.address.city = "上海";
System.out.println(p1.address.city); // 上海 → 影响原对象
System.out.println(p2.address.city); // 上海
}
}
深拷贝
重写 clone() 方法实现深拷贝
在 clone() 方法中,不仅要调用 super.clone(),还要对引用类型字段手动进行拷贝(通常也调用其 clone() 方法,要求被引用的类也支持克隆)。
java
class Address implements Cloneable {
String city;
Address(String city) { this.city = city; }
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // Address 内部只有基本类型/不可变,浅拷贝即可
}
}
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 cloned = (Person) super.clone(); // 浅拷贝基础字段
cloned.address = (Address) address.clone(); // 深拷贝 address
return cloned;
}
}
使用序列化实现深拷贝
将对象写入流再从流中读出,可以自动实现深拷贝(要求所有引用类型都实现 Serializable 接口)。序列化方式的优点是不需要为每个类手动编写拷贝逻辑,但要求所有涉及类都实现 Serializable,且性能相对较低。
java
import java.io.*;
class Address implements Serializable {
String city;
Address(String city) { this.city = city; }
}
class Person implements Serializable {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 深拷贝方法
public Person deepCopy() {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(this);
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (Person) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
使用复制构造函数或工厂方法
手动编写一个构造函数,接收同类型对象并逐一复制字段,对于引用类型也递归复制。这种方式清晰直观,但需要为每个类编写拷贝逻辑,且当对象图复杂时容易遗漏。
java
class Address {
String city;
Address(String city) { this.city = city; }
// 复制构造函数
Address(Address other) {
this.city = other.city;
}
}
class Person {
String name;
Address address;
Person(String name, Address address) {
this.name = name;
this.address = address;
}
// 复制构造函数(深拷贝)
Person(Person other) {
this.name = other.name;
this.address = new Address(other.address); // 复制 address
}
}