深拷贝和浅拷贝

news2024/11/13 11:14:47

目录

一.Java的Cloneable和clone()方法

1.Object类中的clone()

2.实现Cloneable接口的类

3.通过clone()生成对象的特点

二.深拷贝和浅拷贝

1.浅拷贝

2.深拷贝

3.实现深拷贝的两种方法

1.一种是递归的进行拷贝

2.Json字符串的方式进行深拷贝


一.Java的Cloneable和clone()方法

1.Object类中的clone()

以下是Java中Object类中clone()方法,我们可以看到clone()方法是没有方法体的,因为clone是一个native类型的代码,具体的代码实现在JVM的c++代码中实现,Java只是调用.

2.实现Cloneable接口的类

以下是Cloneable接口的内容,我们可以看到这个接口里面并没有实际的说明内容,这个接口的实现表示实现的类重写了clone()方法,可以进行对象的克隆.

现在我们实现Cloneable接口来创建一个类,这个类重写了clone(),并且根据重写的规则,这个方法的修饰必须比protected的权限更大,因此可以使用public方法,而且Object类中返回值是Object,我们这里重写的返回值可以为Dog,因为重写的规则规定返回值必须是instanceof Object,所以返回值可以为Dog.

public class Dog implements Cloneable{
    String name;
    int age;

    public Dog() {
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

现在我们尝试用Dog类中的clone方法来克隆一个完全一样的对象

    public static void main(String[] args) throws CloneNotSupportedException {
        Dog dog1 = new Dog("张选宁", 2);
        Dog dog2 = dog1.clone();
        System.out.println(dog1);
        System.out.println(dog2);
        System.out.println(dog1==dog2);
    }

现在我们来思考一个问题,dog1和dog2是否指向的是同一个对象呢?我们有什么方法来验证是否为同一个对象呢?

这里提供两种方法来判断

  1. 使用==号来进行判断

            //"==" 比较的是两个引用是否指向同一个对象
            System.out.println(dog1==dog2);//false

  2.  修改一个对象的属性,检查另一个对象的属性是否发生改变
        dog1.name="薛程朗";
        System.out.println(dog1.name); //薛程朗
        System.out.println(dog2.name); //张选宁
    

因此我们从以上两个结果可以判断出,clone()方法产生的对象是指向不同引用的.

3.通过clone()生成对象的特点

上面我们通过两个结果已经总结出来了:clone()方法产生的对象是指向不同引用的.现在我们来具体的理解以下这两个对象.

根据下面两个图我们可以很直观的看出,这两个对象的地址不一样(也就是引用不一样),当改变一个对象的属性值的时候,另一个是不会发生改变的,clone()只是产生了一个属性相同的另一个对象

那么我们再来思考一个问题 ,如果这个类中包含了其他类型的对象,这个时候这个对象该如何拷贝呢?这就引出了我们的深拷贝和浅拷贝的概念了.

二.深拷贝和浅拷贝

以下是一个包含其他对象的类

public class Person implements Cloneable {
    String name;
    //包含了其他类型的对象
    Dog dog;

    public Person() {
    }

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

    public Person(String name, Dog dog) {
        this.name = name;
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", dog=" + dog +
                '}';
    }
}

1.浅拷贝

接下来我们来验证是否克隆person1对象的时候,是否会将Person类中的Dog对象重现创建对象,还是仅仅是引用的复制(也就是地址相同的对象(同一个对象))

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("czj", new Dog("张选宁", 3));
        Person person2 = person1.clone();
        System.out.println(person1.dog==person2.dog);//ture
        person1.dog.name="薛程朗";
        System.out.println(person1.dog.name);//薛程朗
        System.out.println(person2.dog.name);//薛程朗
    }

通过验证我们可以很清楚的看到仅仅是引用的复制,本质上里面的dog对象还是同一个对象,形象一点来说,也就是一个人,通过克隆技术又克隆出来了一个一模一样的人,但他们拥有的狗还是同一个狗.

接下来我们还是通过画图来明确这种拷贝方式的原理

 这就是浅拷贝,只是将对象里面的对象引用进行了简单的拷贝,并没有将里面的对象进行new新建

接下来是网络上的定义:

浅拷贝是指只复制了对象的引用,新对象和原对象引用的是同一个对象。因此,当修改其中一个对象时,另一个对象也会受到影响。浅拷贝通常只能复制基本数据类型和对其他对象的引用,而不能复制其所引用的对象本身。

2.深拷贝

深拷贝其实就是不仅将需要克隆的对象进行拷贝了,也将对象里面的对象也进行了重新的拷贝.

这只是简单举例,不论有多少个对象,都会进行一一的进行拷贝处理,这种方法就叫做深拷贝.

接下来是网络上的定义:

深拷贝则是指复制了对象本身,而不仅仅是对象的引用。因此,新对象和原对象在内存中拥有不同的地址,彼此之间没有任何关联。深拷贝通常能够完全复制原对象,包括所有的属性和引用对象,因此比浅拷贝更加安全和可靠。

3.实现深拷贝的两种方法

1.一种是递归的进行拷贝

具体应该将Person类中的clone()方法进行如下的修改

    @Override
    public Person clone() throws CloneNotSupportedException {
        Person person=(Person) super.clone();
        Dog dog1 = person.dog.clone();
        person.dog=dog1;
        return person;
    }

但是这种方法已经是很老旧的方法了,现在计算机实现已经不采用了这种方法了,现在使用的深拷贝方法是第二种方法.

2.Json字符串的方式进行深拷贝

使用JSON字符串进行深拷贝需要以下步骤:

1.将对象转换为JSON字符串:使用JSON库,如Jackson、Gson或FastJSON,将需要拷贝的对象转换为JSON字符串。

2.将JSON字符串转换回对象:使用JSON库将JSON字符串转换回一个新的对象。

这将创建一个新的对象,其属性与原始对象相同,但是它们不会共享对象引用,而是创建新的引用。

下面是一个使用Jackson库进行深拷贝的示例代码:

import com.fasterxml.jackson.databind.ObjectMapper;

public class DeepCopyUtils {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static <T> T deepCopy(T object) throws Exception {
        String jsonString = objectMapper.writeValueAsString(object);
        return objectMapper.readValue(jsonString, (Class<T>) object.getClass());
    }
}

在这个示例代码中,我们使用Jackson的ObjectMapper类将对象转换为JSON字符串,并将其转换回新的对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/417155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

No.037<软考>《(高项)备考大全》【第21章】项目组合管理

【第21章】项目组合管理1 考试相关2 项目组合管理2.1 项目组合管理、项目集管理、项目管理异同2.2 项目组合管理过程组3 练习题参考答案1 考试相关 选择1分必考 案例概率低&#xff0c;知识点看一遍即可 2 项目组合管理 1、项目组合是将项目、项目集&#xff0c;以及其他方面…

2023年MathorCup数学建模赛题浅析

MathorCup俗称妈杯&#xff0c;是除了美赛国赛外参赛人数首屈一指的比赛&#xff0c;而我们的妈杯今天也如期开赛。今年的妈杯难度&#xff0c;至少在我看来应该是2023年截至目前来讲最难的一场比赛。问题的设置、背景的选取等各个方面都吐露着我要难死你们的想法。难度是恒定的…

Servlet、SpringMVC、SpringBoot整合Thymeleaf汇总

介绍 模板引擎&#xff0c;与JSP、JSTL类似。 好处是&#xff1a;直接写在HTML文件中&#xff0c;服务器可以解析&#xff0c;浏览器也可以解析&#xff0c;实现了动静分离&#xff0c;并未破坏html结构&#xff0c;即使无网络、不通过后端渲染也能在浏览器成功打开&#xff…

kettle——数据清洗(数据表-->文本文件)

实验步骤&#xff1a; 1.数据表&#xff08;图片加分析&#xff0c;创建表的过程和对应的字段及记录&#xff09; ①选择数据库 ②创建表结构 ③插入数据 2.kettle连接模块&#xff08;图片加分析,每个模块实现的功能&#xff09; ①新建“转换”文件,”文件”——>“新建…

JAVA开发运维(Jenkins中踩的坑)

最近尝试通过Jenkins来自动化部署项目&#xff0c;没想到还踩了很多坑。Jenkins部署的基本原理&#xff1a; 通过Jenkins服务器拉取gitlab上的代码进行打包&#xff0c;推送到目标服务器上&#xff0c;并运行启动脚本。 那么Jenkins就要解决三个问题。 1.连接上目标服务器 …

电子行业应如何实施数字工厂管理系统

随着信息技术的快速发展&#xff0c;电子制造企业也正在逐步做好数字化转型&#xff0c;而数字工厂管理系统便是数字化管理中的一个重要系统。数字工厂系统可以帮助电子企业实现生产过程的自动化、智能化和可视化&#xff0c;提高生产效率&#xff0c;降低生产成本&#xff0c;…

2023香港国际创科展开幕,欧科云链受邀参展

4月12日&#xff0c;由香港特区政府、香港贸易发展局主办的首届香港国际创科展&#xff08;InnoEX&#xff09;在香港会展中心开幕&#xff0c;欧科云链&#xff08;01499.HK)作为全球领先的Web3科技企业受邀参展。香港国际创科展现场图 此次创科展上&#xff0c;欧科云链向公众…

【RocketMQ】负载均衡源码分析

RocketMQ在集群模式下&#xff0c;同一个消费组内&#xff0c;一个消息队列同一时间只能分配给组内的某一个消费者&#xff0c;也就是一条消息只能被组内的一个消费者进行消费&#xff0c;为了合理的对消息队列进行分配&#xff0c;于是就有了负载均衡。 接下来以集群模式下的消…

智优ERP的升级版智优E3_ERP,可以自定义列,和自定义打印公司logo

新版的智优E3_ERP系统&#xff0c;新增了许多供自定义的列。 系统能够解决的企业管理问题&#xff1a; 一、日常的出入库管理、收付款管理、往来对账、移动加权平均成本核算、以及相关数据的查询分析&#xff1b; 二、订单的跟单管理&#xff08;包括销售跟单、采购跟单、生产…

ElasticSearch常用查询操作

ES查询 一般我们使用ES最多的就是查询&#xff0c;今天就讲一下ES的查询。这里我是建了一个person的索引。 "person" : {"aliases" : { },"mappings" : {"properties" : {"address" : {"type" : "text"…

[LeetCode周赛复盘] 第 102 场双周赛20230415

[LeetCode周赛复盘] 第 102 场双周赛20230415 一、本周周赛总结二、 6333. 查询网格图中每一列的宽度1. 题目描述2. 思路分析3. 代码实现三、6334. 一个数组所有前缀的分数1. 题目描述2. 思路分析3. 代码实现四、6335. 二叉树的堂兄弟节点 II1. 题目描述2. 思路分析3. 代码实现…

English Learning - L2 第 15 次小组纠音 助动词弱读和重音节奏 2023.4.15 周六

English Learning - L2 第 15 次小组纠音 助动词弱读和重音节奏 2023.4.15 周六共性问题have has /hv/ /hz/ 弱读成 /həv/ /həz/fine left /faɪn/ /left/late changed train /leɪt/ /ʧeɪnʤd/ /treɪn/ 中的 eɪmoment problem time /ˈməʊmənt/ /ˈprɒbləm/ /taɪm…

4.10~4.11学习总结

ER图的学习&#xff1a; 学习了ER图相关知识&#xff0c;并绘制了项目大概的ER图 详细笔记博客&#xff1a;http://t.csdn.cn/YOJxq MySQL的学习&#xff1a; 函数 学习了字符串函数&#xff0c;数值函数&#xff0c;日期函数&#xff0c;流程函数。 约束 作用于表中字段的规则…

改善Instagram客户服务的6个技巧

Instagram仍然是全球前四大社交网络&#xff0c;按用户数量排名。它通过其创新的过滤器、内容创建工具、视频和卷轴选项继续增长并推动流量。这是一个平台&#xff0c;世界顶级名人和有影响力的人可以为全球用户提供有趣和令人印象深刻的内容。 但不仅仅是一个娱乐平台&#xf…

Nestjs实战干货-概况-异常过滤器-Exception filters

异常过滤器 Nest 带有一个内置的异常层&#xff0c;负责处理应用程序中所有未处理的异常。当应用程序代码未处理异常时&#xff0c;该层会捕获该异常&#xff0c;然后自动发送适当的用户友好响应。 开箱即用&#xff0c;此操作由内置的全局异常过滤器执行&#xff0c;该过滤器…

三、Locust任务(task)详解

当一个负载测试开始时&#xff0c;将为每个模拟用户创建一个用户类的实例&#xff0c;他们将在自己的绿色线程中开始运行。当这些用户运行时&#xff0c;他们会选择执行的任务&#xff0c;睡眠一段时间&#xff0c;然后选择一个新的任务&#xff0c;如此循环。 这些任务是正常…

二、Java 并发编程(4)

本章概要 Java 中的锁 乐观锁悲观锁自旋锁synchronizedReentrantLocksynchronized 与 ReentrantLock 对比SemaphoreAtomicInteger可重入锁公平锁和非公平锁读写锁共享锁和独占锁重量级锁和轻量级锁偏向锁分段锁同步锁和死锁如何进行锁优化 2.6 Java 中的锁 Java 中的锁主要…

【C语言进阶:动态内存管理】C/C++中程序内存区域的划分

⚡C/C中程序内存区域的划分 C/C程序内存分配的几个区域&#xff1a; 栈区&#xff08;stack&#xff09;&#xff1a;在执行函数时&#xff0c;函数内局部变量的存储单元都可以在栈上创建&#xff0c;函数执行结 束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指…

day8 互斥锁/读写锁的概念及使用、死锁的避免

目录 互斥锁的概念和使用 线程通信 - 互斥 互斥锁的创建和销毁 互斥锁的创建 互斥锁的销毁 互斥锁的使用 申请锁 释放锁 互斥锁的概念和使用 线程通信 - 互斥 临界资源&#xff1a; 一次只允许一个任务&#xff08;进程、线程&#xff09;访问的共享资源&#xff1b…

Maven-依赖管理

一. 依赖管理 1. maven-依赖管理-依赖配置 依赖&#xff1a;指当前项目运行所需要的jar包。一个项目中可以引入多个依赖&#xff1a; 例如&#xff1a;在当前工程中&#xff0c;我们需要用到logback来记录日志&#xff0c;此时就可以在maven工程的pom.xml文件中&#xff0c…