java常用API深克隆和浅克隆


Java 中提供了两种克隆(clone)对象的方式,分别是深克隆和浅克隆。

浅克隆是指仅仅克隆了对象本身,而对象内部引用的其他对象并没有克隆。也就是说,新对象和原对象引用的是同一个内部对象。

深克隆则是指将对象及其内部所有引用对象都进行克隆,也就是说,新对象和原对象引用的是不同的内部对象。

在 Java 中,要实现深克隆和浅克隆,可以使用 Cloneable 接口和 clone() 方法来完成。需要注意的是,使用 clone() 方法进行克隆操作时,被克隆的对象必须实现 Cloneable 接口,并重写 clone() 方法。

下面是浅克隆和深克隆的示例代码:

浅克隆示例代码:

public 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 {
        return super.clone();
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        List<String> hobbies = new ArrayList<>();
        hobbies.add("reading");
        hobbies.add("swimming");
        Person p1 = new Person("Alice", 20, hobbies);
        Person p2 = (Person) p1.clone();
        System.out.println(p1.getHobbies() == p2.getHobbies()); // true
    }
}

上述代码中,Person 类实现了 Cloneable 接口,并重写了 clone() 方法。在 Test 类中,我们创建了一个 Person 对象 p1,并将它的 hobbies 属性赋值为一个 List 对象。然后,我们克隆了 p1 对象,并将结果赋值给 p2 对象。最后,我们比较了 p1 和 p2 对象的 hobbies 属性,发现它们引用的是同一个 List 对象,因此输出结果为 true。

深克隆示例代码:

public 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 set
    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();
    person.hobbies = new ArrayList<>(this.hobbies);
    return person;
}
}

public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
List<String> hobbies = new ArrayList<>();
hobbies.add("reading");
hobbies.add("swimming");
Person p1 = new Person("Alice", 20, hobbies);
Person p2 = (Person) p1.clone();
System.out.println(p1.getHobbies() == p2.getHobbies()); // false
}
}

上述代码中,在 Person 类的 clone() 方法中,我们首先调用了 super.clone() 方法,得到了一个新的 Person 对象 person。然后,我们将 p1 对象的 hobbies 属性的引用复制到 person 对象的 hobbies 属性中。由于新的 hobbies 属性引用的是一个新的 ArrayList 对象,因此 p1 和 p2 对象引用的 hobbies 对象是不同的,输出结果为 false。

需要注意的是,深克隆需要对所有的引用类型属性进行克隆操作,否则克隆出来的对象仍然可能引用原对象中的属性。在上述示例代码中,我们对 hobbies 属性进行了克隆操作,但如果 Person 类中还有其他引用类型的属性,同样需要进行相应的克隆操作。

另外,需要注意的是,clone() 方法是一种浅拷贝的方式,它不会调用任何构造函数,而是直接在内存中复制一个对象。因此,如果要克隆的对象的构造函数中有副作用,那么克隆后的对象可能会有不同的行为。另外,如果要克隆的对象有 final 类型的属性,那么这些属性将无法被克隆,因为 final 类型的属性在初始化后不允许被修改。

在实际开发中,如果需要进行深克隆,推荐使用一些第三方库,例如 Apache Commons Lang、Google Guava 或 FastJSON 等,这些库中提供了相应的工具类和方法,可以方便地进行深克隆操作。另外,如果可以使用 Java 8 及以上版本,也可以使用 Java 中提供的 Stream API 对对象进行深克隆。


原文链接:codingdict.net