1. 浅克隆 (Shallow Copy)
浅克隆指的是创建一个新的对象,并将原始对象的字段值复制到新对象中。如果字段是基本数据类型(如 int
、char
等),则直接复制这些值。如果字段是引用类型(如数组、对象等),则复制的是引用,而不是创建新的对象。因此,浅克隆后的对象和原始对象共享引用类型的字段(例如,引用类型的字段指向相同的内存地址)。
浅克隆的特点:
- 对于基本数据类型,进行的是值的复制。
- 对于引用类型,进行的是引用的复制,即原始对象和克隆对象中的引用指向同一个内存位置。
示例:
class Person {
String name;
int age;
int[] scores;
public Person(String name, int age, int[] scores) {
this.name = name;
this.age = age;
this.scores = scores;
}
// 浅克隆
public Person shallowClone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
public class ShallowCopyExample {
public static void main(String[] args) {
int[] scores = {85, 90, 88};
Person person1 = new Person("Tom", 20, scores);
Person person2 = person1.shallowClone();
// 修改 person2 的 scores 数组
person2.scores[0] = 100;
// person1 的 scores 数组也会被修改,因为是引用类型的浅克隆
System.out.println("person1 scores[0]: " + person1.scores[0]); // 100
System.out.println("person2 scores[0]: " + person2.scores[0]); // 100
}
}
输出:
person1 scores[0]: 100
person2 scores[0]: 100
在这个例子中,person1
和 person2
共享相同的 scores
数组,修改其中一个对象的数组会影响到另一个对象。
2. 深克隆 (Deep Copy)
深克隆指的是创建一个新的对象,并递归地复制原始对象中的所有字段。对于基本数据类型,值会被直接复制;对于引用类型,会复制出一份新的对象,这意味着原始对象和克隆对象中的引用类型字段指向的是不同的内存位置。因此,深克隆的对象与原始对象完全独立,即使修改克隆对象的引用类型字段,也不会影响原始对象。
深克隆的特点:
- 对于基本数据类型,进行的是值的复制。
- 对于引用类型,进行的是对象的递归复制,创建新的对象,使得原始对象和克隆对象中的引用类型字段指向不同的内存位置。
举个例子:
class Person implements Cloneable {
String name;
int age;
int[] scores;
public Person(String name, int age, int[] scores) {
this.name = name;
this.age = age;
this.scores = scores;
}
// 深克隆
@Override
public Person clone() {
try {
Person cloned = (Person) super.clone();
cloned.scores = cloned.scores.clone(); // 对 scores 进行深克隆
return cloned;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
public class DeepCopyExample {
public static void main(String[] args) {
int[] scores = {85, 90, 88};
Person person1 = new Person("Tom", 20, scores);
Person person2 = person1.clone();
// 修改 person2 的 scores 数组
person2.scores[0] = 100;
// person1 的 scores 数组不会受到影响
System.out.println("person1 scores[0]: " + person1.scores[0]); // 85
System.out.println("person2 scores[0]: " + person2.scores[0]); // 100
}
}
输出:
person1 scores[0]: 85
person2 scores[0]: 100
在这个例子中,person1
和 person2
拥有不同的 scores
数组。修改其中一个对象的数组不会影响另一个对象。
3. 深克隆与浅克隆的区别总结
特性 | 浅克隆 (Shallow Copy) | 深克隆 (Deep Copy) |
---|---|---|
基本数据类型 | 复制基本数据类型的值 | 同样复制基本数据类型的值 |
引用类型(数组、对象等) | 复制引用类型的引用,原始对象与克隆对象共享引用类型字段 | 复制引用类型的对象,原始对象与克隆对象的引用类型字段指向不同的内存地址 |
适用场景 | 对于不包含嵌套对象或引用类型的简单对象,或者希望共享引用对象时 | 当需要确保克隆对象与原对象完全独立,尤其是当对象中包含嵌套引用对象时 |
4. 深克隆与浅克隆的实现方式
-
浅克隆可以通过实现
Cloneable
接口并重写clone()
方法来实现,Java 的Object
类提供了clone()
方法,默认实现是浅克隆。 -
深克隆需要手动处理引用类型的字段,通过调用
clone()
或使用其他方法(如序列化)来复制引用类型的对象。
深克隆的其他实现方式:
选择使用浅克隆还是深克隆,取决于具体的需求,尤其是在对象中是否包含可变的引用类型字段时。
-
序列化方式:通过将对象序列化后再反序列化来实现深克隆。这样可以自动处理所有字段的复制,包括引用类型字段。
import java.io.*; public class DeepCloneUsingSerialization { public static <T> T deepClone(T obj) throws IOException, ClassNotFoundException { // 写入字节流 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(obj); out.flush(); // 读取字节流并返回新对象 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bis); return (T) in.readObject(); } }
总结
- 浅克隆只复制对象本身,不会递归复制引用类型字段,因此它们会共享引用类型的数据。
- 深克隆会递归地复制对象中的所有字段,包括引用类型字段,因此它们互不影响,完全独立。