自学内容网 自学内容网

Java浅拷贝和深拷贝

在Java中,对象的复制可以分为浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。这两种拷贝方式的主要区别在于对对象内部的引用类型的处理上。

浅拷贝

浅拷贝是指创建一个新对象,这个新对象的属性和原来对象完全相同,对于非基本类型的属性(如对象、数组等),只是复制其引用而已,也就是说,原对象和拷贝对象的该属性仍然指向同一个内存地址。因此,如果修改了其中一个对象的状态,就可能会影响到另一个对象。在Java中,实现浅拷贝的一种简单方式是使用对象的clone()方法,但需要注意的是,要实现浅拷贝,被拷贝的类需要实现Cloneable接口,通过接口的名字也能猜到,它的作用是允许类被拷贝,否则执行clone()方法的时候会抛出 CloneNotSupportedException 异常。
示例代码:

class Cat {
    String name = "黏黏";
}

public class Person implements Cloneable{
    Cat cat;
    public Person(Cat cat){
        this.cat = cat;
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        Cat cat = new Cat();
        Person person1 = new Person(cat);
        Person person2 = (Person)person1.clone();
        // 改变person2的cat的名字,也会影响到person1的cat
        person2.cat.name = "糊糊";
        System.out.println(person1.cat.name);
    }
}
//输出:糊糊

以上示例中,person1拥有一只猫,我们复制person1得到person2。这时,我们修改person2的猫的名字,person1的猫的名字也随之改变,由此可见,我们只复制了person1,而没有复制它的猫,person1和person2拥有的是同一只猫。

深拷贝

深拷贝则是创建一个新对象,并且递归地复制原对象的所有属性,包括引用类型属性所指向的对象。这意味着,深拷贝后的新对象和原对象在内容上完全相等,但是地址不同,修改一个对象的属性不会影响到另一个对象。深拷贝用clone()方法实现比较麻烦,所有嵌套的对象都要重写clone()方法。更为简便的方式是利用序列化/反序列化等机制,通过序列化/反序列得到的对象就是深拷贝的对象。

示例代码:

class Cat implements Serializable {
    String name = "黏黏";
}

public class Person implements Serializable {
    Cat cat;
    public Person(Cat cat){
        this.cat = cat;
    }
    public static void main(String[] args) throws Exception {
        Cat cat = new Cat();
        Person person1 = new Person(cat);

        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(person1);

        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        Person person2 = (Person)ois.readObject();

        // 改变person2的cat的名字,也会影响到person1的cat
        person2.cat.name = "糊糊";
        System.out.println(person1.cat.name);
    }
}
//输出:黏黏

注意序列化对象需要所有嵌套的类都实现Serializhezable接口,否则会抛出NotSerializableException异常,与Cloneable接口一样,Serializhezable也是一个标记接口,没有定义方法。

浅拷贝应用场景

浅拷贝可以实现

  1. 修改父对象而不影响子对象:如果你需要创建一个新对象,但仅计划修改顶层属性,而不打算改变内部子对象的状态,浅拷贝是一个好选择。例如,在配置文件或参数设置中,你可能只想改变某些顶层参数,保持内部结构不变。
  2. 实现默认参数:在函数中使用浅拷贝可以避免因误修改默认参数而导致的副作用。这样,每次函数调用时,默认参数都是原始值的一个副本,而不是直接引用原值。

深拷贝应用场景

  1. 完全独立的对象复制:当你需要一个与原对象完全独立的新对象,包括所有层级的子对象时,应使用深拷贝。这在进行复杂的算法操作、数据分析或测试不同的数据配置时尤为重要,确保修改新对象不会影响到原始数据。
  2. 安全地分享数据:在多线程或并发编程中,为了防止不同线程间的无意修改共享数据,可以通过深拷贝为每个线程提供独立的数据副本,从而减少竞态条件和同步问题。
  3. 缓存和备份:在需要创建数据的快照或备份时,深拷贝能确保获得一个完整且独立的副本。这对于实现撤销或重做功能、数据版本控制等场景至关重要。
  4. 处理不可变数据结构:在某些编程范式或库中,鼓励或要求使用不可变数据。对这些数据结构进行任何修改都会返回一个新的结构。在这种情况下,深拷贝是自然的选择,以符合不可变性的要求。
     

原文地址:https://blog.csdn.net/qq_38875964/article/details/143024516

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!