在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中是不可变的。如果列表中的元素是可变的对象,那么你可能需要进一步实现这些元素的深克隆。