在Java中,对象的拷贝有两种方式:浅拷贝和深拷贝。它们分别代表了不同的拷贝方式,拷贝出的新对象与原始对象之间存在一定的差异。本文将详细介绍浅拷贝和深拷贝的概念、特点和实现方式,并且通过实例进行解析。

 一、浅拷贝

 浅拷贝是指在对一个对象进行拷贝时,只拷贝对象本身和其中的基本数据类型,而不拷贝对象内部的引用类型。因此,在浅拷贝的对象中,引用类型的变量指向的依旧是原始对象中的引用。

 在Java中,实现浅拷贝可以使用Object类的clone()方法,或者手动重写类的clone()方法。下面是一个示例:

class Person implements Cloneable {
    private String name;
    private Address address;
    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Address {
    private String city;
    public Address(String city) {
        this.city = city;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Address address = new Address("Beijing");
        Person person1 = new Person("Tom", address);
        Person person2 = (Person) person1.clone();
        System.out.println(person1 == person2); // false
        System.out.println(person1.getAddress() == person2.getAddress()); // true
    }
}

在上述代码中,我们定义了一个Person类和Address类。Person类中包含一个引用类型的成员变量address。使用Object类的clone()方法进行拷贝,并且在Person类中实现了Cloneable接口,并重写了clone()方法,使得Person类可以进行拷贝。

 在main函数中,我们创建了一个Person对象person1,其中包含一个Address对象。接着,我们使用person1的clone()方法创建了一个新的Person对象person2,并使用“==”判断person1和person2是否是同一对象。结果为false,证明两个对象是不同的。接下来,我们使用“==”判断person1和person2中的address是否是同一对象,结果为true,即两个对象的address成员变量指向的是同一个地址。

 总的来说,浅拷贝只是将原始对象的引用类型成员变量复制到新的对象中,因此新对象中的引用类型成员变量与原始对象中的成员变量指向同一对象。如果原始对象中的引用类型成员变量发生变化,新对象中的引用类型成员变量也会随之变化。

 二、深拷贝

 深拷贝是指在对一个对象进行拷贝时,不仅拷贝对象本身和其中的基本数据类型,同时也拷贝对象内部的引用类型。因此,在深拷贝的对象中,引用类型的变量指向的是全新的对象。

 在Java中,实现深拷贝的方式比较多,可以使用对象的序列化、手动编写clone()方法等。下面是一个使用对象序列化来实现深拷贝的例子:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test {
    public static void main(String[] args) throws Exception {
        Address address = new Address("Beijing");
        Person person1 = new Person("Tom", address);
        Person person2 = (Person) deepCopy(person1);
        System.out.println(person1 == person2); // false
        System.out.println(person1.getAddress() == person2.getAddress()); // false
    }
    private static Object deepCopy(Object obj) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
}
class Person implements Serializable {
    private String name;
    private Address address;
     public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
    public Address getAddress() {
        return address;
    }
}
class Address implements Serializable {
    private String city;
     public Address(String city) {
        this.city = city;
    }
}

在上述代码中,我们定义了一个Person类和Address类,并且让它们都实现了Serializable接口。在main函数中,我们创建了一个Person对象person1,其中包含一个Address对象。接着,我们使用deepCopy()方法创建了一个新的Person对象person2,并使用“==”判断person1和person2是否是同一对象。结果为false,证明两个对象是不同的。接下来,我们使用“==”判断person1和person2中的address是否是同一对象,结果为false,即两个对象的address成员变量指向的是不同的地址。

 在上述代码中,我们使用了一个deepCopy()方法来实现对象的深拷贝。该方法使用对象的序列化和反序列化来实现深拷贝。首先,将原始对象序列化成字节数组,然后再将字节数组反序列化成新的对象。这样可以保证复制出的新对象与原始对象完全独立,不会相互影响。

 总结:

 浅拷贝和深拷贝是Java中常用的两种对象拷贝方式。浅拷贝只会复制对象内部的基本数据类型和引用类型变量的引用,而深拷贝会将对象内部所有的基本类型和引用类型都复制一份。使用clone()方法和重写clone()方法可以实现浅拷贝,使用对象序列化或手动复制可以实现深拷贝。在实现对象拷贝时需要根据具体情况选择合适的拷贝方式,以保证复制出的新对象能够满足应用需求。

转自:https://blog.csdn.net/2301_77181435/article/details/130646783