java ArrayList的深拷贝与浅拷贝问题

什么是深拷贝和浅拷贝?

在Java中,我们经常使用集合类来存储和操作对象。其中ArrayList是一种常用的动态数组(可变长度的数组)实现。但是在使用过程中,会遇到对象拷贝的问题:是深拷贝还是浅拷贝?

深拷贝和浅拷贝是针对对象进行复制、克隆的概念,假设有一个对象A,它有一个成员变量B,而B又有一个成员变量C,那么进行拷贝时,如果只是将A拷贝一份,那么B与其指向的C仍是原来A中的对象。此时,拷贝出来的对象与原对象虽然有相同的属性值,但却是两个相互独立的对象。这就是深拷贝。而只拷贝A对象,而B和C仍然是原对象A所指向的对象,则被称为浅拷贝。

ArrayList的浅拷贝和深拷贝

当我们进行ArrayList的拷贝时,Java提供两种方法:

  1. Object.clone()方法
  2. 通过循环新建对象复制所有元素

第一种方法是浅拷贝,由于ArrayList中的元素通常是对象引用,clone()方法只会复制对象的引用而不是对象本身,因此,如果我们对ArrayList中的元素进行修改操作,原列表和新列表中引用的同一个对象的内容都会改变。因此在我们使用ArrayList时,对于含有对象引用的数据结构,在使用clone()方法时应当特别小心。

下面我们通过两个示例来演示ArrayList的浅拷贝和深拷贝

示例一:浅拷贝

public class ShallowCopy {

    public static void main(String[] args) {
        //创建一个原始对象ArrayList
        ArrayList<String> originalList = new ArrayList<>();
        originalList.add("Apple");
        originalList.add("Banana");
        originalList.add("Cherry");

        //进行对象的浅拷贝
        ArrayList<String> clonedList = (ArrayList<String>)originalList.clone();

        //修改拷贝后的对象
        clonedList.set(1, "Watermelon");

        //输出结果
        System.out.println("Original ArrayList: " + originalList);
        System.out.println("Cloned ArrayList: " + clonedList);
    }
}

输出结果:

Original ArrayList: [Apple, Banana, Cherry]
Cloned ArrayList: [Apple, Watermelon, Cherry]

可以发现,尽管我们只是修改了拷贝后的对象,但原始对象的内容也随之改变了。

示例二:深拷贝

class Person implements Cloneable {
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "[name=" + name + ", age=" + age + "]";
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class DeepCopy {

    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一个原始对象ArrayList
        ArrayList<Person> originalList = new ArrayList<>();
        originalList.add(new Person("Tom", 20));
        originalList.add(new Person("Jack", 21));
        originalList.add(new Person("Jerry", 22));

        //进行对象的深拷贝
        ArrayList<Person> clonedList = new ArrayList<>();
        for (Person person : originalList) {
           clonedList.add((Person)person.clone());
        }

        //修改拷贝后的对象
        clonedList.get(1).age = 25;

        //输出结果
        System.out.println("Original ArrayList: " + originalList);
        System.out.println("Cloned ArrayList: " + clonedList);
    }
}

输出结果:

Original ArrayList: [[name=Tom, age=20], [name=Jack, age=21], [name=Jerry, age=22]]
Cloned ArrayList: [[name=Tom, age=20], [name=Jack, age=25], [name=Jerry, age=22]]

可以发现,尽管我们只是修改了拷贝后的对象,但原始对象的内容没有发生变化。这证明我们成功进行了深拷贝。

总之,当我们需要对包含对象引用的数据结构进行拷贝时,应该根据实际需要选择浅拷贝还是深拷贝。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java ArrayList的深拷贝与浅拷贝问题 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • java 命名空间 命名规则第2/2页

    Java命名空间和命名规则 Java中的命名空间是一种用于组织和管理类、接口、变量和其他命名实体的机制。命名空间可以帮助避免命名冲突,并提供代码的可读性和可维护性。以下是Java命名空间和命名规则的详细攻略。 包(Package) 包是Java中用于组织和管理类和接口的主要机制。包提供了一种层次结构,可以将相关的类和接口组织在一起。以下是包的命名规则: 包名…

    other 2023年10月13日
    00
  • C语言中网络地址与二进制数之间转换的函数小结

    下面是本人对于“C语言中网络地址与二进制数之间转换的函数小结”的攻略: 网络地址与二进制数的转换 在进行网络编程时,经常需要将IP地址和端口号表示成二进制数(例如:IPv4地址是32位的二进制数),也需要将二进制数转换成IP地址和端口号表示。 这里推荐C语言提供的一些库函数以及方法。 函数1:inet_pton 函数inet_pton可以将一个字符串形式的I…

    other 2023年6月26日
    00
  • Java 判断IP地址的合法性实例详解

    Java 判断IP地址的合法性实例详解 在Java中,我们可以使用正则表达式来判断一个IP地址的合法性。下面是一个完整的攻略,包含了两个示例说明。 步骤一:编写正则表达式 首先,我们需要编写一个正则表达式来匹配合法的IP地址。一个合法的IP地址由四个数字组成,每个数字的取值范围是0到255,数字之间用点号(.)分隔。下面是一个示例的正则表达式: String…

    other 2023年7月31日
    00
  • 抖音个人账号可以转为企业账号吗?二者区别介绍

    抖音个人账号可以转为企业账号吗?二者区别介绍 可以转为企业账号 抖音个人账号可以转为企业账号。转换为企业账号后,可以获取更多的功能和服务,例如数据分析、广告投放等,有利于个人或公司进行品牌宣传和业务推广。 以下是将个人账号转换为企业账号的步骤: 进入“我的”页面,点击右上角的“设置”按钮。 在设置界面中找到“账号管理”,进入账号管理页面。 选择“切换到企业账…

    other 2023年6月27日
    00
  • lua使用string.split(str ‘ ‘)

    当然,我可以为您提供有关“Lua使用string.split(str, delimiter)”的完整攻略,以下是详细说明: Lua使用string.split(str, delimiter)函数 在Lua中,如果需要将一个字符串按照指定的分隔符进行分割,可以使用string.split(str, delimiter)函数。该函数将返回一个由分割后的子字符串组…

    other 2023年5月7日
    00
  • vmware虚拟机下ubuntu安装vmwaretools详解

    VMWare虚拟机下Ubuntu安装VMWare Tools详解 在VMWare虚拟机中安装VMWare Tools可以让Ubuntu操作系统更好地适配于VMWare环境,从而提高操作系统的性能。本文将详细介绍如何在VMWare虚拟机下安装VMWare Tools。 步骤1:安装VMWare Tools前的准备工作 在安装VMWare Tools之前,首先需…

    其他 2023年3月29日
    00
  • Java子类实例化总是默认调用父类的无参构造操作

    Java子类实例化总是默认调用父类的无参构造操作 父类构造器的作用 在Java中,构造器是一种特殊类型的方法,主要用于创建和初始化对象。在对象生成过程中,当一个对象被创建时,总是先执行其父类的构造方法,然后再执行自己的构造方法完成自身的初始化操作。因此,一个子类初始化之前,总是要先对父类进行初始化。 子类默认调用父类无参构造器的原因 在Java中,如果一个类…

    other 2023年6月26日
    00
  • PropertyGrid自定义控件使用详解

    标题:PropertyGrid自定义控件使用详解 简介 PropertyGrid 是 Windows 系统中提供的一个用于显示和编辑对象属性的控件。该控件提供了良好的可扩展性,我们可以通过自定义控件来实现需求,本文将详细讲解如何使用 PropertyGrid 自定义控件。 步骤说明 步骤一:新建自定义控件 开发环境为 Visual Studio 2019。 …

    other 2023年6月26日
    00
合作推广
合作推广
分享本页
返回顶部