Interview
Java 浅拷贝和深拷贝

在Java编程中,浅拷贝和深拷贝是对象复制的两种方式。它们的主要区别在于是否复制对象的引用对象。以下是对这两种拷贝方式的详细说明:

浅拷贝 (Shallow Copy)

浅拷贝是对象的字段逐位复制。也就是说,对于对象的非引用类型(基本数据类型)字段,会直接复制其值;对于对象的引用类型字段(如数组、对象等),只会复制引用,而不会复制实际对象。结果是,原对象和浅拷贝对象共享同一个引用对象。

浅拷贝的实现方式

  1. 使用clone()方法
  • 实现Cloneable接口,并重写clone()方法。
class Person implements Cloneable {
    String name;
    int age;
    Address address;
 
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
 
class Address {
    String city;
    String street;
 
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
}
 
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("New York", "5th Avenue");
        Person person1 = new Person("John", 30, address);
        Person person2 = (Person) person1.clone();
 
        System.out.println(person1.address == person2.address); // 输出 true
    }
}

深拷贝 (Deep Copy)

深拷贝会创建一个新对象,并递归地复制所有引用类型的字段。也就是说,深拷贝会复制对象的所有子对象,确保原对象和复制对象之间没有共享的引用对象。

深拷贝的实现方式

  1. 通过重写clone()方法
  • clone()方法中手动拷贝所有引用对象。
class Person implements Cloneable {
    String name;
    int age;
    Address address;
 
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone(); // 深拷贝Address
        return cloned;
    }
}
 
class Address implements Cloneable {
    String city;
    String street;
 
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
 
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("New York", "5th Avenue");
        Person person1 = new Person("John", 30, address);
        Person person2 = (Person) person1.clone();
 
        System.out.println(person1.address == person2.address); // 输出 false
    }
}
  1. 通过序列化和反序列化实现深拷贝
  • 将对象序列化为字节流,再反序列化为新对象。这种方法需要对象和所有子对象实现Serializable接口。
import java.io.*;
 
class Person implements Serializable {
    String name;
    int age;
    Address address;
 
    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
}
 
class Address implements Serializable {
    String city;
    String street;
 
    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
}
 
public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Address address = new Address("New York", "5th Avenue");
        Person person1 = new Person("John", 30, address);
 
        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(person1);
 
        // 反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Person person2 = (Person) ois.readObject();
 
        System.out.println(person1.address == person2.address); // 输出 false
    }
}

总结

  • 浅拷贝:复制对象的基本类型字段,对引用类型字段只复制引用,不复制实际对象。
  • 深拷贝:复制对象的基本类型字段和引用类型字段,引用类型字段的实际对象也会被递归地复制。

选择使用哪种拷贝方式取决于具体需求和应用场景。在需要完全独立的副本时,使用深拷贝;在不需要完全独立的副本时,使用浅拷贝。