Java中的集合及深拷贝与浅拷贝

Java中的集合及深拷贝与浅拷贝

Java是一种面向对象的编程语言,其中集合是常用的数据结构之一,具有方便快捷的特点。在Java开发中,我们常常需要对集合进行复制(拷贝)操作。但是,拷贝操作并不是简单的复制,而应该分为浅拷贝和深拷贝两种不同的方式,本文将分别介绍Java中集合的浅拷贝和深拷贝实现方法。

集合简介

Java中的集合是一种用于存储对象的容器,其中包括List、Set、Map等多种类型。集合的特点是可以动态地增加、删除和修改其中的元素。Java中的集合框架分为两个接口:Collection和Map,其中Collection是所有集合接口的根接口,其常用的子接口包括List、Set和Queue。Map接口表示键-值映射,常用的实现类有HashMap和TreeMap。

在这里插入图片描述

浅拷贝

浅拷贝是指拷贝对象时,只复制对象的引用而不是对象本身。这意味着拷贝后的对象与原始对象共享同一个内存地址,对于引用类型的成员变量,拷贝后的对象和原始对象都指向同一个实例。

在Java中,可以通过调用Object类的clone()方法实现浅拷贝。该方法会复制对象的字段,但是对于引用类型的字段,仅复制其引用,而不会复制引用指向的对象。

下面是一个示例代码,演示了如何使用clone()方法实现集合的浅拷贝。

import java.util.ArrayList;
import java.util.List;

class Person implements Cloneable {
    private String name;
    private int age;
    private List<String> hobbies;

    public Person(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        this.hobbies = hobbies;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class ShallowCopyDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        List<Person> list1 = new ArrayList<>();
        List<String> hobbies = new ArrayList<>();
        hobbies.add("reading");
        hobbies.add("swimming");
        Person person1 = new Person("Tom", 20, hobbies);
        list1.add(person1);
        List<Person> list2 = (List<Person>) ((ArrayList<Person>) list1).clone();
        System.out.println(list1 == list2);
        System.out.println(list1.get(0) == list2.get(0));
        System.out.println(list1.get(0).getHobbies() == list2.get(0).getHobbies());
    }
}

在上面的示例代码中,我们创建了一个Person类,其中包含一个List类型的成员变量hobbies。然后,我们创建了一个List类型的集合list1,并向其中添加一个Person对象person1。接着,我们通过调用list1的clone()方法创建了一个新的集合list2,然后比较list1和list2、person1和list2中的Person对象以及person1和list2中的Person对象的hobbies是否相同。可以看到,由于是浅拷贝,list1和list2、person1和list2中的Person对象及其hobbies都是共享同一块内存空间的。

深拷贝

与浅拷贝不同,深拷贝是指拷贝对象时,不仅复制对象的引用,而且复制引用指向的对象,即创建一个全新的对象,并将原始对象中的所有字段值复制到新对象中。这样做的好处是,新对象和原始对象之间不存在任何关联,对新对象的修改不会影响原始对象。

在Java中,实现深拷贝的方法有多种,下面介绍两种常用的方式。

1. 序列化与反序列化

Java中的序列化可以将对象转换为字节流,而反序列化则可以将字节流还原为对象。利用这一特性,我们可以通过将对象序列化为字节流,然后再反序列化成新对象的方式实现深拷贝。

下面是一个示例代码,演示了如何使用序列化和反序列化实现集合的深拷贝。

import java.io.*;
import java.util.ArrayList;
import java.util.List;

class Person implements Serializable {
    private String name;
    private int age;
    private List<String> hobbies;

    public Person(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        this.hobbies = hobbies;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }
}

public class DeepCopyDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        List<Person> list1 = new ArrayList<>();
        List<String> hobbies = new ArrayList<>();
        hobbies.add("reading");
        hobbies.add("swimming");
        Person person1 = new Person("Tom", 20, hobbies);
        list1.add(person1);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(list1);
        oos.flush();
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        List<Person> list2 = (List<Person>) ois.readObject();
        System.out.println(list1 == list2);
        System.out.println(list1.get(0) == list2.get(0));
        System.out.println(list1.get(0).getHobbies() == list2.get(0).getHobbies());
    }
}

在上面的示例代码中,我们创建了一个Person类,其中包含一个List类型的成员变量hobbies。然后,我们创建了一个List类型的集合list1,并向其中添加一个Person对象person1。接着,我们通过将list1序列化为字节流,然后再将字节流反序列化为新的List对象list2,实现了深拷贝。最后,我们比较list1和list2、person1和list2中的Person对象以及person1和list2中的Person对象的hobbies是否相同。可以看到,由于是深拷贝,list1和list2、person1和list2中的Person对象及其hobbies均不是共享同一块内存空间的。

2. 手动递归拷贝

手动递归拷贝是另一种实现深拷贝的方式,其思路是先创建一个空的新对象,然后递归地复制原始对象中的所有字段值到新对象中。对于引用类型的字段,需要继续递归拷贝其指向的对象,直到所有字段值均被复制到新对象中。

下面是一个示例代码,演示了如何使用手动递归拷贝实现集合的深拷贝。

import java.util.ArrayList;
import java.util.List;

class Person {
    private String name;
    private int age;
    private List<String> hobbies;

    public Person(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        this.hobbies = hobbies;
    }

    public String getName() {
        return name;
    }

    publicvoid setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    public Person deepCopy() {
        List<String> newHobbies = new ArrayList<>();
        for (String hobby : hobbies) {
            newHobbies.add(hobby);
        }
        return new Person(name, age, newHobbies);
    }
}

public class DeepCopyDemo2 {
    public static void main(String[] args) {
        List<Person> list1 = new ArrayList<>();
        List<String> hobbies = new ArrayList<>();
        hobbies.add("reading");
        hobbies.add("swimming");
        Person person1 = new Person("Tom", 20, hobbies);
        list1.add(person1);
        List<Person> list2 = new ArrayList<>();
        for (Person person : list1) {
            list2.add(person.deepCopy());
        }
        System.out.println(list1 == list2);
        System.out.println(list1.get(0) == list2.get(0));
        System.out.println(list1.get(0).getHobbies() == list2.get(0).getHobbies());
    }
}

在上面的示例代码中,我们创建了一个Person类,其中包含一个List类型的成员变量hobbies。然后,我们创建了一个List类型的集合list1,并向其中添加一个Person对象person1。接着,我们通过手动递归拷贝的方式,创建了一个新的集合list2,并将list1中的所有Person对象递归拷贝到list2中。最后,我们比较list1和list2、person1和list2中的Person对象以及person1和list2中的Person对象的hobbies是否相同。可以看到,由于是深拷贝,list1和list2、person1和list2中的Person对象及其hobbies均不是共享同一块内存空间的。

总结

在Java中,集合是一种常用的数据结构,而集合的拷贝操作又分为浅拷贝和深拷贝两种方式。浅拷贝只复制对象的引用,而深拷贝则复制引用指向的对象,创建一个全新的对象。实现浅拷贝可以通过调用Object类的clone()方法或者手动复制对象的字段实现,而实现深拷贝可以通过序列化与反序列化或者手动递归拷贝实现。在实际开发中,我们应该根据具体情况选择合适的拷贝方式,以保证代码的正确性和性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java深拷贝浅拷贝是两种常用的对象拷贝方式。浅拷贝只会复制对象内部的基本数据类型和引用类型变量的引用,当引用指向的值改变时,拷贝出的新对象也会跟着变化。而深拷贝则是与原来的对象完全隔离,互不影响。 要实现浅拷贝,可以使用clone()方法或重写clone()方法。clone()方法是Object类的一个方法,它会创建并返回对象的一个副本,但这个副本仅仅是原始对象的浅拷贝。我们还可以通过重写clone()方法,实现自定义的浅拷贝操作。 要实现深拷贝,则有两种方法。一种是使用对象序列化,即将对象转换为字节流,然后再转换回对象。这种方法会复制对象内部所有的基本类型和引用类型,从而实现深拷贝。另一种方法是手动复制对象的每个属性,将其复制到一个新对象。这种方法需要我们手动处理每个属性的复制过程,确保所有的属性都被复制并且互不影响。 在选择深拷贝还是浅拷贝时,我们需要根据具体情况来决定。如果我们希望拷贝后的新对象与原对象完全隔离,并且对新对象的修改不会影响原对象,那么应该选择深拷贝。如果我们希望拷贝后的新对象与原对象共享一些引用类型的属性,并且对新对象的修改会影响原对象,那么可以选择浅拷贝。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java浅拷贝深拷贝](https://blog.csdn.net/2301_77181435/article/details/130646783)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [java深拷贝浅拷贝](https://blog.csdn.net/weixin_45771158/article/details/125730734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stormjun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值