浅析Java中clone()方法浅克隆与深度克隆
在Java中,clone()方法是对象复制的方式,它可以将一个对象的内容复制到另一个对象中。clone()方法实现的是浅克隆,也就是只复制对象的基本类型属性或对其他对象的引用,而不会复制其他对象的内容。如果需要在两个对象之间实现完全复制,则需要实现深度克隆。
在Java中,Java对象的类层级结构都是基于Object类的。Object类有一个clone()方法,从中派生的类都可以继承和重写该方法。然而,clone()方法是一个非常特殊的方法,只有实现了Cloneable接口的类才能调用该方法。如果未实现Cloneable接口,将会抛出CloneNotSupportedException异常。
浅克隆:
浅克隆会复制对象中的基本类型属性(如:int、double、String等),还会复制对象中的引用类型属性,但仅仅只是复制引用的地址,而不是引用中的内容(也就是说,新的对象和原始的对象会指向相同的对象)。
示例代码:
class Person implements Cloneable{
private String name;
private int age;
private List<String> hobbies;
public Person(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
List<String> hobbies = new ArrayList<String>();
hobbies.add("swimming");
hobbies.add("fishing");
Person person1 = new Person("John", 20, hobbies);
Person person2 = (Person) person1.clone();
System.out.println("p1: " + person1);
System.out.println("p2: " + person2);
System.out.println("=================================");
// 修改person1的属性值
person1.getHobbies().add("reading");
person1.setName("Peter");
person1.setAge(30);
System.out.println("p1 after modification: " + person1);
System.out.println("p2 after modification: " + person2);
System.out.println("=================================");
}
}
输出:
p1: Person{name='John', age=20, hobbies=[swimming, fishing]}
p2: Person{name='John', age=20, hobbies=[swimming, fishing]}
=================================
p1 after modification: Person{name='Peter', age=30, hobbies=[swimming, fishing, reading]}
p2 after modification: Person{name='John', age=20, hobbies=[swimming, fishing, reading]}
=================================
从输出可以看出,person1和person2的基本类型属性都被复制了,但person1的hobbies属性为List类型,是引用类型,所以person2的hobbies也指向了person1中的hobbies,当person1的hobbies属性进行修改时,person2的hobbies也会发生改变。
深度克隆:
深度克隆是完全复制对象的方式,它不仅复制对象中的基本类型属性,还会递归复制对象中的其他对象。
示例代码:
class Person implements Cloneable{
private String name;
private int age;
private List<String> hobbies;
public Person(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
// 深度克隆
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
List<String> hobbies = new ArrayList<String>();
for (String hobby : this.getHobbies()) {
hobbies.add(hobby);
}
person.setHobbies(hobbies);
return person;
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
List<String> hobbies = new ArrayList<String>();
hobbies.add("swimming");
hobbies.add("fishing");
Person person1 = new Person("John", 20, hobbies);
Person person2 = (Person) person1.clone();
System.out.println("p1: " + person1);
System.out.println("p2: " + person2);
System.out.println("=================================");
// 修改person1的属性值
person1.getHobbies().add("reading");
person1.setName("Peter");
person1.setAge(30);
System.out.println("p1 after modification: " + person1);
System.out.println("p2 after modification: " + person2);
System.out.println("=================================");
}
}
输出:
p1: Person{name='John', age=20, hobbies=[swimming, fishing]}
p2: Person{name='John', age=20, hobbies=[swimming, fishing]}
=================================
p1 after modification: Person{name='Peter', age=30, hobbies=[swimming, fishing, reading]}
p2 after modification: Person{name='John', age=20, hobbies=[swimming, fishing]}
=================================
从输出可以看出,当person1的hobbies属性进行修改时,person2的hobbies没有发生改变,这是因为通过深度克隆我们已经对person1和person2的hobbies进行了分别复制,它们没有指向相同的对象。
总结:
使用clone()方法进行克隆对象时,如果待复制的对象中没有引用类型的数据,可以使用浅克隆进行复制,如果待复制的对象中有引用类型的数据,建议使用深度克隆,否则复制出的对象与原始对象之间可能会存在引用共享的问题,从而会造成不必要的影响。
