在Java中,对象的克隆(Cloning)是指创建一个对象的副本。Java提供了两种克隆对象的方式:浅克隆(Shallow Clone)和深克隆(Deep Clone)。浅克隆创建的对象副本与原对象共享引用类型的成员变量,而深克隆则创建一个完全独立的对象副本,包括所有成员变量的副本。
浅克隆
浅克隆通过实现Cloneable
接口和重写clone
方法来实现。Cloneable
接口是一个标记接口,没有任何方法,用于指示该类的对象可以被克隆。
实现步骤:
- 实现
Cloneable
接口。 - 重写
clone
方法,调用super.clone()
方法。
编程示例:
class Person implements Cloneable {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class ShallowCloneExample {
public static void main(String[] args) {
try {
Person original = new Person("Alice", 30);
Person cloned = (Person) original.clone();
System.out.println("Original: " + original);
System.out.println("Cloned: " + cloned);
// 修改克隆对象的属性
cloned.name = "Bob";
cloned.age = 25;
System.out.println("After modification:");
System.out.println("Original: " + original);
System.out.println("Cloned: " + cloned);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
解释:
Person
类实现了Cloneable
接口,并重写了clone
方法。- 在
main
方法中,创建了一个Person
对象original
,并通过调用clone
方法创建了cloned
对象。 - 修改
cloned
对象的属性不会影响original
对象的属性,因为基本数据类型的成员变量是独立的。
深克隆
深克隆需要手动复制所有引用类型的成员变量,以确保克隆对象和原对象完全独立。深克隆可以通过以下几种方式实现:
- 手动复制所有引用类型的成员变量。
- 使用序列化(Serialization)。
- 使用第三方库(如Apache Commons的
SerializationUtils
)。
手动复制引用类型的成员变量
编程示例:
class Address implements Cloneable {
String city;
public Address(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Address{city='" + city + "'}";
}
}
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(); // 手动复制引用类型的成员变量
return cloned;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", address=" + address + "}";
}
}
public class DeepCloneExample {
public static void main(String[] args) {
try {
Address address = new Address("New York");
Person original = new Person("Alice", 30, address);
Person cloned = (Person) original.clone();
System.out.println("Original: " + original);
System.out.println("Cloned: " + cloned);
// 修改克隆对象的引用类型成员变量
cloned.address.city = "Los Angeles";
System.out.println("After modification:");
System.out.println("Original: " + original);
System.out.println("Cloned: " + cloned);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
解释:
Address
类实现了Cloneable
接口,并重写了clone
方法。Person
类实现了Cloneable
接口,并在clone
方法中手动复制了address
成员变量。- 修改
cloned
对象的address
属性不会影响original
对象的address
属性,因为address
成员变量也是独立的。
使用序列化实现深克隆
编程示例:
import java.io.*;
class Address implements Serializable {
String city;
public Address(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address{city='" + city + "'}";
}
}
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;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", address=" + address + "}";
}
public Person deepClone() throws IOException, ClassNotFoundException {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
}
}
public class DeepCloneSerializationExample {
public static void main(String[] args) {
try {
Address address = new Address("New York");
Person original = new Person("Alice", 30, address);
Person cloned = original.deepClone();
System.out.println("Original: " + original);
System.out.println("Cloned: " + cloned);
// 修改克隆对象的引用类型成员变量
cloned.address.city = "Los Angeles";
System.out.println("After modification:");
System.out.println("Original: " + original);
System.out.println("Cloned: " + cloned);
} catch (Exception e) {
e.printStackTrace();
}
}
}
解释:
Address
类和Person
类实现了Serializable
接口。Person
类中定义了一个deepClone
方法,通过序列化和反序列化实现深克隆。- 修改
cloned
对象的address
属性不会影响original
对象的address
属性,因为address
成员变量也是独立的。
总结
- 浅克隆:通过实现
Cloneable
接口和重写clone
方法实现,适用于基本数据类型的成员变量。 - 深克隆:通过手动复制引用类型的成员变量或使用序列化实现,确保克隆对象和原对象完全独立。
通过这些方法,开发者可以根据需求选择合适的克隆方式,实现对象的克隆操作。