MST

星途 面试题库

面试题:Java中clone方法的深拷贝与浅拷贝

在Java中使用clone方法实现对象拷贝时,深拷贝和浅拷贝有什么区别?请举例说明如何分别实现深拷贝和浅拷贝,特别是当对象包含其他对象引用时。
36.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

深拷贝和浅拷贝的区别

  1. 浅拷贝
    • 浅拷贝会创建一个新对象,新对象的基本数据类型字段值与原对象相同,对于对象引用类型字段,新对象和原对象的该字段引用同一个对象。
    • 也就是说,如果原对象中某个引用类型字段指向的对象发生改变,浅拷贝后的对象中该字段指向的对象也会改变。
  2. 深拷贝
    • 深拷贝不仅会创建一个新对象,新对象的基本数据类型字段值与原对象相同,而且对于对象引用类型字段,会递归地复制其引用的对象,即新对象和原对象的引用类型字段指向不同的对象。
    • 这样,原对象中某个引用类型字段指向的对象发生改变,不会影响深拷贝后的对象中该字段指向的对象。

浅拷贝实现示例

class Address {
    private String city;
    public Address(String city) {
        this.city = city;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}

class Person implements Cloneable {
    private String name;
    private Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public Address getAddress() {
        return address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class ShallowCopyExample {
    public static void main(String[] args) {
        try {
            Address address = new Address("Beijing");
            Person person1 = new Person("Tom", address);
            Person person2 = (Person) person1.clone();

            System.out.println("Before change:");
            System.out.println("Person1 address city: " + person1.getAddress().getCity());
            System.out.println("Person2 address city: " + person2.getAddress().getCity());

            person1.getAddress().setCity("Shanghai");

            System.out.println("After change:");
            System.out.println("Person1 address city: " + person1.getAddress().getCity());
            System.out.println("Person2 address city: " + person2.getAddress().getCity());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在上述示例中,Person类实现了Cloneable接口并重写了clone方法,这里只是调用了super.clone()实现浅拷贝。当修改person1address对象的city属性时,person2address对象的city属性也会改变。

深拷贝实现示例

class AddressDeepCopy implements Cloneable {
    private String city;
    public AddressDeepCopy(String city) {
        this.city = city;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class PersonDeepCopy implements Cloneable {
    private String name;
    private AddressDeepCopy address;

    public PersonDeepCopy(String name, AddressDeepCopy address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public AddressDeepCopy getAddress() {
        return address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        PersonDeepCopy cloned = (PersonDeepCopy) super.clone();
        cloned.address = (AddressDeepCopy) address.clone();
        return cloned;
    }
}

public class DeepCopyExample {
    public static void main(String[] args) {
        try {
            AddressDeepCopy address = new AddressDeepCopy("Beijing");
            PersonDeepCopy person1 = new PersonDeepCopy("Tom", address);
            PersonDeepCopy person2 = (PersonDeepCopy) person1.clone();

            System.out.println("Before change:");
            System.out.println("Person1 address city: " + person1.getAddress().getCity());
            System.out.println("Person2 address city: " + person2.getAddress().getCity());

            person1.getAddress().setCity("Shanghai");

            System.out.println("After change:");
            System.out.println("Person1 address city: " + person1.getAddress().getCity());
            System.out.println("Person2 address city: " + person2.getAddress().getCity());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

在这个深拷贝示例中,PersonDeepCopy类的clone方法不仅调用super.clone()克隆自身,还对address对象进行了克隆,使得person1person2address对象是不同的,修改person1address对象的city属性,不会影响person2address对象的city属性。