首页 > 编程语言 >“深入探讨Java中的对象拷贝:浅拷贝与深拷贝的差异与应用“

“深入探讨Java中的对象拷贝:浅拷贝与深拷贝的差异与应用“

时间:2024-06-06 14:01:38浏览次数:30  
标签:Java 对象 clone address 深入探讨 Person Address 拷贝

        前言:在Java编程中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是两个非常重要的概念。它们涉及到对象在内存中的复制方式,对于理解对象的引用、内存管理以及数据安全都至关重要。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

先让我们看一下本文的大致内容:

目录

1.深拷贝与浅拷贝的概念

(1)浅拷贝

(2)深拷贝

2.浅拷贝的实现

3.深拷贝的实现

4.深浅拷贝的作用

浅拷贝的作用:

深拷贝的作用:


1.深拷贝与浅拷贝的概念

        ——在了解Java中是如何实现对象的深浅拷贝之前,我们需要先了解一下什么是深拷贝、浅拷贝:

(1)浅拷贝

        在浅拷贝中,只复制对象本身,而不复制对象引用的内容。这意味着,如果对象中包含了引用类型的成员变量,那么这些成员变量的引用将会被复制,但是它们仍然指向相同的内存地址。因此,对于引用类型成员变量的修改会影响到原始对象和拷贝对象。

(2)深拷贝

        与浅拷贝不同,深拷贝会递归地复制对象及其所有引用的对象,直到所有对象都被复制到一个新的内存地址上。这样,原始对象和拷贝对象完全独立,彼此的修改不会相互影响。

        嗯嗯嗯......感觉看了和没看没什么区别,还是不太能理解到底什么是Java中的深浅拷贝,那么我们使用一个生活中的案例来解释一下:

浅拷贝的情景:

        ——如果你选择了浅拷贝,那么你会简单地把整个礼物篮进行复制,然后送给你的朋友。在这种情况下,你的朋友会得到一个看起来一模一样的礼物篮。然而,当你的朋友拆开礼物篮,他们发现里面的食品和饰品并没有改变,他们是和你的礼物篮里的相同的食品和饰品。

深拷贝的情景:

        ——相比之下,如果你选择了深拷贝,那么你会仔细地把礼物篮里的每一样东西都复制一份,然后把这些复制品装进一个新的礼物篮里,送给你的朋友。在这种情况下,你的朋友得到的是一个全新的礼物篮,里面的食品和饰品和你的礼物篮里的完全一样。但是,现在他们拥有的是独立于你的礼物篮的新的食品和饰品。

不知道上面的生活案例有没有使你更好的理解Java中的深浅拷贝,如果还是没有,那么直接往下看即可!

大致的了解了什么是Java中的深浅拷贝之后,那么我们又该如何使用代码去实现它们呢?

2.浅拷贝的实现

        在Java中,实现浅拷贝通常使用clone()方法。该方法会创建一个新对象,并将原始对象的所有字段值复制到新对象中。但是需要注意的是,对于引用类型的成员变量,仍然是浅拷贝,即复制的是引用而不是对象本身。

        下面是在Java中实现浅拷贝的详细步骤:

1.实现Cloneable接口:

class MyClass implements Cloneable {
    // 类的定义
}

 2.重写clone()方法并调用super.clone()

class MyClass implements Cloneable {
    // 类的定义

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

3.在使用时捕获CloneNotSupportedException异常:

try {
    MyClass copy = (MyClass) original.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

4.强制转换:由于clone()方法返回的是Object类型,因此在使用时需要进行类型转换。

try {
    MyClass copy = (MyClass) original.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

       

         这就是实现Java中浅拷贝的四步实现流程,相信你仔细的读完上边的代码之后,对Java中浅拷贝的实现流程已经有了初步的理解了,现在让我们使用一个完整的案例,来实现一下Java中的浅拷贝:    

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

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

    // Getter and setter 方法

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

class Address {
    private String city;
    
    public Address(String city) {
        this.city = city;
    }

    // Getter and setter 方法
}

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

        try {
            Person person2 = (Person) person1.clone();
            // 输出: true
            System.out.println(person1.getAddress() == person2.getAddress()); 
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

以上代码演示了一个浅拷贝的例子。让我来解释一下它的执行过程和输出:

  1. 首先,我们定义了两个类:PersonAddressPerson类有一个name属性和一个address属性,而Address类只有一个city属性。

  2. ShallowCopyExample类的main方法中,我们创建了一个Address对象,表示Alice的地址是"New York"。然后,我们创建了一个Person对象person1,传入了名字"Alice"和上面创建的Address对象。

  3. 接着,我们调用person1.clone()方法进行浅拷贝。由于Person类实现了Cloneable接口并重写了clone()方法,因此它支持克隆操作。在clone()方法内部,我们调用了super.clone()来复制Person对象本身,但是对于address属性,只是复制了其引用,而没有对Address对象进行深度复制。

  4. 输出语句System.out.println(person1.getAddress() == person2.getAddress());比较了person1person2address属性是否是同一个对象。由于浅拷贝只是复制了引用,所以person1person2address属性指向的是同一个Address对象,因此输出结果为true

这样我们就大致的了解了在Java中如何去实现对象的浅拷贝了。

3.深拷贝的实现

        在Java中实现深拷贝相对于浅拷贝来说更为复杂,因为需要确保对象及其引用的所有对象都被复制到新的内存地址上。

        下面是在Java中实现深拷贝的详细流程:

1.实现Cloneable接口:同样,为了使用clone()方法,需要确保类实现了Cloneable接口。

class MyClass implements Cloneable {
    // 类的定义
}

2.重写clone()方法:在重写的clone()方法中,除了调用super.clone()来复制对象本身之外,还需要递归地复制所有引用的对象。

class MyClass implements Cloneable {
    private AnotherClass anotherObject;

    public MyClass(AnotherClass anotherObject) {
        this.anotherObject = anotherObject;
    }

    // Getter and setter 方法

    @Override
    public Object clone() throws CloneNotSupportedException {
        MyClass clonedObject = (MyClass) super.clone();
        // 对引用类型的成员变量进行深度复制
        clonedObject.anotherObject = (AnotherClass) anotherObject.clone();
        return clonedObject;
    }
}

3.在引用类型的类中同样实现深拷贝:如果类中有成员变量是引用类型,那么需要在该引用类型的类中同样实现深拷贝。

class AnotherClass implements Cloneable {
    // 类的定义

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

4.调用clone()方法:现在可以调用clone()方法来获取深拷贝的对象。

public class DeepCopyExample {
    public static void main(String[] args) {
        AnotherClass anotherObject = new AnotherClass();
        MyClass original = new MyClass(anotherObject);
        MyClass deepCopy = null;

        try {
            deepCopy = (MyClass) original.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

        这就是实现Java中深拷贝的四步实现流程,当然,现在让我们使用一个完整的案例,来实现一下Java中的深拷贝:    

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

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

    // Getter and setter 方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clonedPerson = (Person) super.clone();
        clonedPerson.address = (Address) this.address.clone();
        return clonedPerson;
    }
}

class Address implements Cloneable {
    private String city;
    
    public Address(String city) {
        this.city = city;
    }

    // Getter and setter 方法

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

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

        try {
            Person person2 = (Person) person1.clone();
            // 输出: false
            System.out.println(person1.getAddress() == person2.getAddress()); 
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

让我解释一下代码的主要部分:

  1. Person 类和 Address 类都实现了 Cloneable 接口,这是为了表明它们可以被克隆。

  2. Person 类中,有一个私有字段 address,类型为 AddressPerson 类的构造函数用于初始化这个字段。

  3. Person 类的 clone() 方法首先调用了 super.clone(),这会复制 Person 对象本身。然后,它对 address 字段进行了深拷贝,即创建了一个新的 Address 对象,并将其赋值给 clonedPersonaddress 字段。

  4. Address 类中的 clone() 方法也是调用了 super.clone(),实现了浅拷贝,因为 Address 类只有一个字段,且该字段为不可变类型。

  5. main() 方法中,首先创建了一个 Address 对象和一个 Person 对象。然后,通过调用 clone() 方法,创建了一个新的 Person 对象 person2,其中包含了新的 Address 对象。

  6. 最后,通过比较 person1person2 的地址字段,可以看到它们不相同,这表明在克隆过程中进行了深拷贝。

这样我们就大致的了解了在Java中如何去实现对象的深拷贝了。

4.深浅拷贝的作用

        了解完了Java中的深浅拷贝之后,那么其有什么用呢?

浅拷贝的作用:

  1. 节省内存空间:浅拷贝只复制对象本身,不会复制对象引用的内容,因此在某些情况下可以节省内存空间。

  2. 提高对象创建速度:由于浅拷贝只复制对象本身,因此复制过程相对较快。

  3. 适用于不包含引用类型成员变量的对象:如果对象中的成员变量都是基本数据类型或者不需要被复制的对象,那么浅拷贝是一个简单有效的复制方式。

深拷贝的作用:

  1. 确保对象的独立性:深拷贝会递归地复制对象及其引用的所有对象,从而确保复制后的对象与原始对象完全独立,对复制对象的修改不会影响原始对象。

  2. 数据安全性:在多线程环境下,深拷贝可以确保对象的数据安全性,因为每个线程都可以操作独立的对象,而不会相互影响。

  3. 避免对象共享的副作用:在某些情况下,对象的共享可能会导致意外的副作用,深拷贝可以避免这种情况的发生,保证数据的一致性和可靠性。

  4. 适用于包含引用类型成员变量的对象:如果对象中包含了引用类型的成员变量,并且需要复制所有引用的对象,那么深拷贝是更合适的选择。

        总的来说,浅拷贝适用于简单对象的复制,可以提高性能和节省内存空间,而深拷贝则适用于需要确保对象独立性和数据安全性的情况,尤其是当对象包含引用类型成员变量时。


以上就是本篇文章的全部内容了~~~

标签:Java,对象,clone,address,深入探讨,Person,Address,拷贝
From: https://blog.csdn.net/2302_80198073/article/details/139497327

相关文章

  • Java中所有的集合可以分为两大类:接口和实现类。
     接口:Collection:是所有集合的根接口,定义了一组操作集合的基本方法,如添加、删除、遍历等。List:是有序的、可重复的集合,继承自Collection接口。Set:是无序的、不可重复的集合,继承自Collection接口。Queue:是队列接口,用于存储按一定顺序访问的元素。Deque:是双端队列接口,可以......
  • JAVA计算机毕业设计基于的儿童疫苗预约系统(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着科技的进步和人们健康意识的增强,儿童疫苗接种已成为保障儿童健康成长的重要措施。然而,传统的疫苗预约方式往往存在诸多不便,如预约流程繁琐、信息......
  • JAVA计算机毕业设计基于的高校党务管理系统(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着高校党建工作的不断深入和发展,党务管理面临着越来越多的挑战。传统的党务管理方式往往依赖于纸质记录和人工操作,效率低下且容易出错。为了提高党......
  • JAVA计算机毕业设计基于的畅游旅游网(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在信息化和全球化的大背景下,旅游业作为现代服务业的重要组成部分,正在经历着前所未有的变革。畅游旅游网作为一个集旅游信息、服务、交易于一体的综合......
  • JAVA计算机毕业设计基于的仓库管理系统(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的迅猛发展和企业规模的不断扩大,仓库管理作为企业运营中不可或缺的一环,面临着日益复杂和多样化的挑战。传统的仓库管理模式依赖于人工操......
  • java:数组和集合(例如ArrayList)的对比
    问题:为什么java里有了array还要有arrayList?(相类比的:python里只有list没有array)答案:因为arrayList是对array的补充,更灵活实用。数组和arrayList都是一维的,但数组可以通过下标直接访问,arrayList只能通过遍历访问;数组能存储基本类型和对象,arrayList只能存对象;数组长度不可变,array......
  • java ArrayIndexOutOfBoundsException数组越界异常
    Java中的ArrayIndexOutOfBoundsException(数组越界异常)是一种运行时异常,表示访问了数组的非法索引位置。在数组中,索引从0开始,并以数组长度减一为上限。如果使用了小于0或大于等于数组长度的索引,就会抛出ArrayIndexOutOfBoundsException异常。以下是一个示例代码,演示了这个异常......
  • Java IOException输入输出异常
    Java的IOException是指在进行输入输出操作时产生的异常。它是IOException类或其子类的实例。IOException是一个受检异常,意味着在方法签名中必须声明或捕获它,否则代码将无法通过编译。常见的IOException包括:FileNotFoundException:当尝试打开文件时,如果指定的文件不存在。EOFE......
  • 基于java ssm vue mysql校园短期闲置资源置换平台系统(源码+lw+部署文档+讲解等)
    前言......
  • 基于java ssm vue mysql网上招投标系统(源码+lw+部署文档+讲解等)
    前言......