在Java中,Object.clone() 方法实现的是浅克隆(Shallow Clone)。这意味着,当你对一个对象调用 clone() 方法时,它会创建一个该对象的新实例,但是新实例中的非静态字段是原始对象对应字段的引用拷贝,而不是字段内容的深拷贝。
简单来说,如果原始对象中的字段是基本数据类型(如int, double等),那么这些字段在新对象中会有相同的值(因为基本数据类型是直接拷贝值)。但是,如果字段是对象类型(即引用类型),那么新对象中的这些字段仅仅是原始对象中相应字段的引用拷贝,它们指向内存中的同一个对象。
为了实现深克隆(Deep Clone),你需要:
- 实现 Cloneable接口(虽然这个接口不包含任何方法,但它是一种约定,表明对象可以被克隆)。
- 重写 clone()方法。在重写的clone()方法中,除了调用super.clone()来创建对象的浅拷贝外,还需要手动对对象中的每一个引用类型字段进行深拷贝(即创建新的对象实例,并复制原始对象的内容到新对象中)。
下面是一个简单的例子,说明如何实现深克隆:
java复制代码
| import java.util.ArrayList;  | |
| import java.util.List;  | |
| class Employee implements Cloneable {  | |
| private String name;  | |
| private List<String> skills;  | |
| // 构造函数、getter和setter省略  | |
| @Override  | |
| protected Object clone() throws CloneNotSupportedException {  | |
| Employee cloned = (Employee) super.clone();  | |
| // 深克隆List  | |
| cloned.skills = new ArrayList<>(skills);  | |
| return cloned;  | |
| }  | |
| }  | |
| public class CloneExample {  | |
| public static void main(String[] args) {  | |
| try {  | |
| Employee emp1 = new Employee();  | |
| emp1.setName("John Doe");  | |
| emp1.setSkills(List.of("Java", "Python"));  | |
| Employee emp2 = (Employee) emp1.clone();  | |
| // 修改emp2的skills列表,不应该影响emp1的skills列表  | |
| emp2.getSkills().add("C++");  | |
| System.out.println(emp1.getSkills()); // 输出 ["Java", "Python"]  | |
| System.out.println(emp2.getSkills()); // 输出 ["Java", "Python", "C++"]  | |
| } catch (CloneNotSupportedException e) {  | |
| e.printStackTrace();  | |
| }  | |
| }  | |
| } | 
注意,上面的例子中,虽然 skills 列表在 clone() 方法中被重新创建,但列表中的元素(这里是字符串)仍然是原始字符串的引用,因为字符串在Java中是不可变的。如果列表中的元素是可变的对象,那么你可能需要进一步实现这些元素的深克隆。