深拷贝与浅拷贝,就是这么简单

1.拷贝的概念

    在编程中,拷贝(或复制)是常见的操作之一。拷贝操作用于创建一个新对象或数据结构,使其具有与原对象或数据结构相同或部分相同的值。

    在进行拷贝操作时,常见的方式有浅拷贝和深拷贝。本文将重点讨论浅拷贝和深拷贝的概念、实现方式以及它们之间的区别。

2.浅拷贝

2.1. 浅拷贝的定义

    浅拷贝是指创建一个新对象,新对象的字段或属性与原对象相同。但对于原对象中的引用类型字段,浅拷贝只会复制其引用而不是实际的数据

2.2. 浅拷贝的实现方式

    当使用浅拷贝时,新对象和原始对象共享相同的数据引用,意味着它们指向内存中相同的对象

    在内存中,每个对象都被分配了一块内存空间。对象的字段存储在该内存空间中,并在字段中保存对其他对象的引用。当进行浅拷贝时,只复制了对象的字段值,而没有创建新的内存空间。

    假设有一个类 Person 如下:

class Person {
    private String name;
    private Address address;

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

    // Getter and setter methods...
}

    其中包含一个 Address 类型的字段 address。现在假设我们有一个原始对象 person1,其中的 address 字段引用了同一个 Address 对象:

Person person1 = new Person("Alice", new Address("City", "Street"));

    当进行浅拷贝时,通过调用 person1.clone() 方法可以得到一个新对象 person2:

Person person2 = person1.clone();

    此时,person1 和 person2 是两个独立的对象,但它们的 name 字段和 address 字段引用相同的内存地址。

2.3 在内存中:

在这里插入图片描述
在这里插入图片描述

     address 字段在 person1 和 person2 中都指向同一个内存地址,即一个共享的 Address 对象。这意味着,当修改了这个共享的 Address 对象时,无论是通过 person1 还是 person2,修改都会反映在两个对象中。

    所以浅拷贝的效果就是对象之间共享相同的引用,对其中一个对象的修改会影响到其他对象。而如果需要实现完全独立的副本,可以使用深拷贝来创建对象的拷贝,并在其中复制引用类型的字段,确保每个副本都有自己独立的对象引用。

    Java中,可以通过以下方式实现浅拷贝:
    实现Cloneable接口,并重写clone()方法。

3. 深拷贝

3.1. 深拷贝的定义

    深拷贝是指创建一个新对象,新对象的所有字段或属性都是原对象的副本。无论是基本类型还是引用类型,都会被复制到新对象中

3.2. 深拷贝的实现方式

    还是上面的例子,下面是深拷贝的实现:

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

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

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public Person clone() throws CloneNotSupportedException {
        Person clonedPerson = (Person) super.clone();
        // 创建一个新的 Address 对象并复制原始对象的 address 字段值
        clonedPerson.address = new Address(this.address.getCity(), this.address.getStreet());
        return clonedPerson;
    }

    // Getter and setter methods...
}

class Address {
    private String city;
    private String street;

    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }

    // Getter and setter methods...
}

    在这个示例中,我们通过覆盖 clone() 方法并在其中手动创建一个新的 Address 对象来实现深拷贝。这样就可以确保每个副本都有自己独立的 Address 对象。

3.3 在内存中

在这里插入图片描述
在这里插入图片描述

    可以看到,person1 和 person2 是两个独立的对象,并且它们的 address 字段引用了不同的内存地址,即各自拥有独立的 Address 对象。因此,对其中一个对象的修改不会影响到另一个对象。

    需要注意的是,在实现深拷贝时,不仅要复制引用类型的字段,还要确保引用类型的字段也实现了可复制(深拷贝)的逻辑,以防止仍然存在共享的引用。

4. 深拷贝与浅拷贝的区别

  • 浅拷贝只复制对象引用,不复制实际数据;
  • 深拷贝会递归复制所有嵌套的对象和数据。

二维表展示对比

深拷贝 (Deep Copy)浅拷贝 (Shallow Copy)
定义创建一个新的对象,将原始对象的所有属性进行递归复制到新对象中创建一个新的对象,将原始对象的属性的引用复制到新对象中
独立性深拷贝后的对象和原始对象是完全独立的,对其中一个对象的修改不会影响另一个对象浅拷贝后的对象和原始对象共享同一个属性对象,对其中一个对象的修改会影响另一个对象
对象关系深拷贝后的对象和原始对象没有任何关联浅拷贝后的对象和原始对象共享同一个属性对象
修改影响对原始对象的修改不会影响深拷贝后的对象对原始对象的修改会影响浅拷贝后的对象
对象复制深拷贝会递归复制所有属性对象,创建一个完全独立的对象浅拷贝只复制属性对象的引用,创建一个共享属性对象的新对象

    通过上述二维表的总结,可以清晰地看到深拷贝和浅拷贝的区别。
    深拷贝创建一个完全独立的对象,对原始对象的修改不会影响深拷贝后的对象;而浅拷贝创建一个共享属性对象的新对象,对原始对象的修改会影响浅拷贝后的对象。
    对于基本数据类型来说,两者一样,都会复制一份新的。

    如果还不太理解,举个例子看会不会好理解些:

  • 浅拷贝就像是在图书馆借阅一本书,并且与其他人共享同一本书。如果你标记了书中的某个页码或做了笔记,其他人看到的书也会有相同的变化。
  • 深拷贝则类似于每个人都有自己独立的书。你可以在你自己的书上做任何标记或笔记,而不会影响到其他人的书。

5. 原型模式与深浅拷贝的关系

    原型模式是一种创建型设计模式,它使用原型实例指定要创建的对象类型,并通过复制这个原型来创建新对象。在原型模式中,拷贝可以是浅拷贝或深拷贝,具体取决于如何实现原型对象的复制。

    在Java中,Cloneable接口就是原型模式的一种实现方式,它使用浅拷贝来复制对象。如果需要实现深拷贝,则需要在clone()方法中手动处理引用类型的字段或属性的拷贝。

    如果想有进一步的了解,可以参看我的上一篇博客
    链接: 设计模式之原型模式–超越实例化的魔法,从复制到创造的无限可能

6. 总结

  • 浅拷贝和深拷贝是常见的拷贝方式,用于创建对象副本。
  • 浅拷贝只复制引用。
  • 深拷贝复制整个对象及其嵌套的对象和数据。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值