欢迎访问宙启技术站
智能推送

浅析Java中clone()方法浅克隆与深度克隆

发布时间:2023-05-18 03:24:57

在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()方法进行克隆对象时,如果待复制的对象中没有引用类型的数据,可以使用浅克隆进行复制,如果待复制的对象中有引用类型的数据,建议使用深度克隆,否则复制出的对象与原始对象之间可能会存在引用共享的问题,从而会造成不必要的影响。