深拷贝和浅拷贝区别

在 Java 中,**深拷贝(Deep Copy)浅拷贝(Shallow Copy)**是指对象复制时,复制的方式和结果的不同。理解这两者的区别非常重要,特别是在处理复杂对象时。浅拷贝和深拷贝的主要区别在于对象内部引用的处理方式。

1. 浅拷贝(Shallow Copy)

浅拷贝是指复制对象时,只复制对象本身,而不会复制对象内部引用的其他对象。也就是说,源对象和目标对象内部的引用类型变量(如数组、对象等)指向相同的内存地址(即它们引用的是相同的对象)。因此,源对象和目标对象共享同一份数据。

浅拷贝的特点:

  • 复制的是对象的“引用”,而非对象所指向的数据。
  • 对象的引用类型字段仍然指向原始对象的内存地址(即浅拷贝并没有创建新的引用对象)。

浅拷贝的代码示例:

class Address {
    String city;

    Address(String city) {
        this.city = city;
    }
}

class Person {
    String name;
    Address address;

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

    // 浅拷贝方法
    public Person shallowCopy() {
        return new Person(this.name, this.address); // 复制的是引用,address 地址相同
    }
}

public class ShallowCopyExample {
    public static void main(String[] args) {
        Address address = new Address("New York");
        Person person1 = new Person("Alice", address);

        // 浅拷贝
        Person person2 = person1.shallowCopy();

        System.out.println(person1.name);        // 输出: Alice
        System.out.println(person2.name);        // 输出: Alice
        System.out.println(person1.address.city); // 输出: New York
        System.out.println(person2.address.city); // 输出: New York

        // 修改 person2 的 address
        person2.address.city = "Los Angeles";
        
        // 由于浅拷贝,person1 和 person2 的 address 是同一个对象
        System.out.println(person1.address.city); // 输出: Los Angeles
        System.out.println(person2.address.city); // 输出: Los Angeles
    }
}

输出结果

Alice
Alice
New York
New York
Los Angeles
Los Angeles

说明

  • person1person2address 引用指向相同的 Address 对象,因此修改 person2address 会影响 person1address
  • 这是因为我们进行了浅拷贝,address 字段只是引用了相同的内存地址。

2. 深拷贝(Deep Copy)

深拷贝是指复制对象时,不仅复制对象本身,而且复制对象内部引用的其他对象。也就是说,深拷贝会创建对象及其所引用的所有对象的副本,源对象和目标对象之间完全独立,它们不会共享任何引用对象。

深拷贝的特点:

  • 复制的是对象及其所有引用的对象,确保新对象的所有引用都指向新创建的对象。
  • 目标对象与源对象在内存中完全独立,修改目标对象的属性不会影响源对象。

深拷贝的代码示例:

class Address {
    String city;

    Address(String city) {
        this.city = city;
    }

    // 深拷贝方法
    public Address deepCopy() {
        return new Address(this.city);  // 创建一个新的 Address 对象
    }
}

class Person {
    String name;
    Address address;

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

    // 深拷贝方法
    public Person deepCopy() {
        // 创建新的 Person 对象,并对 address 进行深拷贝
        return new Person(this.name, this.address.deepCopy());
    }
}

public class DeepCopyExample {
    public static void main(String[] args) {
        Address address = new Address("New York");
        Person person1 = new Person("Alice", address);

        // 深拷贝
        Person person2 = person1.deepCopy();

        System.out.println(person1.name);        // 输出: Alice
        System.out.println(person2.name);        // 输出: Alice
        System.out.println(person1.address.city); // 输出: New York
        System.out.println(person2.address.city); // 输出: New York

        // 修改 person2 的 address
        person2.address.city = "Los Angeles";
        
        // 由于深拷贝,person1 和 person2 的 address 是不同的对象
        System.out.println(person1.address.city); // 输出: New York
        System.out.println(person2.address.city); // 输出: Los Angeles
    }
}

输出结果

Alice
Alice
New York
New York
New York
Los Angeles

说明

  • person1person2address 引用指向不同的对象,person2 修改 address 不会影响 person1
  • 这是因为我们进行了深拷贝,address 字段指向了新创建的 Address 对象。

3. 深拷贝与浅拷贝的对比

特性 浅拷贝(Shallow Copy)深拷贝(Deep Copy)
引用对象的处理 只复制对象本身,不复制对象引用的其他对象。 复制对象本身及其所有引用的对象,确保每个引用指向新的对象。
对象之间的关系 源对象和目标对象共享相同的引用对象。 源对象和目标对象独立,互不影响。
修改影响 修改目标对象会影响源对象,因为它们共享同一引用对象。 修改目标对象不会影响源对象,因为它们不共享任何引用对象。
性能 浅拷贝比深拷贝更高效,因为只涉及对象本身和引用的复制。 深拷贝需要复制整个对象图,性能开销较大。

4. 深拷贝和浅拷贝的实际应用

  • 浅拷贝

    • 适用于不修改对象内部引用的情况下。比如,你只需要复制对象的基本数据,且不关心对象引用类型字段的变化。
    • 常见场景:复制对象用于某些不改变内部引用的操作,如在多线程中共享不可变的对象。
  • 深拷贝

    • 适用于需要复制对象及其引用对象,且这些引用对象的状态不应该被共享的场景。例如,修改一个对象的内部引用数据时不希望影响到其他对象。
    • 常见场景:当对象中包含嵌套的可变对象时,深拷贝能确保每个对象都被独立复制,防止修改一个对象影响到其他对象。
Java碎碎念 文章被收录于专栏

来一杯咖啡,聊聊Java的碎碎念呀

全部评论

相关推荐

timeline一面 3/26二面 4/1HR电话 4/1下午offer 4/3一面1. 项目介绍2. 介绍一下项目中如何使用DDD的3. 对于充血模型的理解4. 你的充血实体中有多少行代码5. 项目中的困难6. DDD为什么落地难,最后怎么落地的7. 介绍一下项目中应用层的服务编排和mq实现的事件驱动通信的区别,以及应用场景8. 讲讲项目中的并发处理操作,以及滑块锁的作用   - 如何防止运营失误   - 如何动态的修改库存9. 项目中令牌桶限流如何实现,作用10. 介绍一下常用的设计模式    - 讲了单例模式和责任链,项目中都有用到11. 讲讲什么是一致性哈希    - 又说了数据倾斜的问题12. 在项目中是如何实现的一致性哈希13. 有写过博客吗    - 写过14. 你最熟悉那一部分的知识点    - 说了mysql,让我自己讲。讲了mysql的索引:数据结构,索引建立考虑什么,索引下推    - 问了redo log和undo log15. 算法:大数和二面1. 项目介绍2. 系统架构的分层是怎么设计的3. 介绍一下每个分层具体的功能4. 领域层的划分5. 实体的设计6. 领域服务的设计7. 领域层和应用层的差别8. 询问个人情况,专业,如何学习9. mysql性能优化问题10. 对ai的了解11. ai如何帮助学习的12. 算法题:    - 数组中第k大的数字,写了两种方法桶排序和快速选择。    - 重排链表
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客企业服务