java中的对象克隆(浅克隆和深克隆)

在实际项目中,一个模型类需要为不同的层提供不同的模型。VO DO DTO

需要将一个对象中的数据克隆到其他对象中。

误区这种形式的代码复制的是引用,即对象在内存中的地址,stu1和stu2两个引用指向的是同一个对象

Student stu1 = new Student(); 
Student stu2 = stu1; 

数据类型分为:基本数据类型和引用数据类型,基本类型的值可以直接复制,引用类型只能复制引用地址。所以浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制

1、浅克隆

在克隆一个对象时,只复制它本身和其中值类型的成员变量,如果有关联的对象,只是将关联对象的引用地址复制过来,并没有创建一个新的关联对象。

实现方式:类实现Cloneable接口,重写Object中的clone方法  

package com.ffyc.javapro.objectClone.demo1;
public class Person implements  Cloneable{
    int num;
    String name;
    
    //get和set方法...

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                '}';
    }
}
package com.ffyc.javapro.objectClone.demo1;
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person(100,"jim");//原型对象
        Person p2 =p1.clone();//克隆的新对象
        System.out.println(p1==p2);//false,实现了克隆
    }
}

以下案例中,有关联的对象address,只是将关联的对象的引用地址复制过来,并没有新创建关联对象,为浅克隆。

public class Address{
    String  address;
	//get和set方法...

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
public class Person implements  Cloneable{
     int num;
     String name;
     Address address;
	//get和set方法...
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.clone();//对象中关联着另一个对象,只是将关联对象的地址复制过来了,并没有重新创建一个新的关联对象
        p2.setName("tom");
        address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向了一个对象

        System.out.println(p1); // jim  西安
        System.out.println(p2); // tom  西安
    }
}

2、深克隆

无论原型对象的成员变量是值类型还是引用类型(关联的对象),都将复制一份给克隆对象。(如果有关联的对象,将关联对象也会重新创建一个)

克隆方式:

  1. 在关联的对象中,也实现Cloneable接口,重写Object中的clone方法,实现多级克隆,但是处理起来比较麻烦。
  2. 使用序列化方式,可以重写创建对象,包含关联的对象。

案例一:相关联的类address也实现了Cloneable接口,重写Object中的clone方法,为深度克隆,但是很麻烦。

public class Address  implements Cloneable{//实现了Cloneable接口
    String  address;
   //get和set方法...
    
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

    @Override
    protected Address clone() throws CloneNotSupportedException {//重写Object中的clone方法
        return (Address)super.clone();
    }
}
public class Person implements  Cloneable{
     int num;
     String name;
     Address address;   
	//get和set方法...
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        person.address = (Address)address.clone();//深度复制  联同person中关联的对象也一同克隆.
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.clone();
        p2.setName("tom");
        address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向不同的对象

        System.out.println(p1); // jim   西安
        System.out.println(p2); // tom   汉中
    }
}

案例二:实现了Serializable。把Person写到流里面,然后读进来,重新创建一个对象

import java.io.Serializable;
public class Address  implements Serializable {
     String  address;
    //get和set方法...

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
import java.io.*;
public class Person implements Serializable {
     int num;
     String name;
     Address address;
    //get和set方法...
    
    //自定义克隆方法
    public Person myclone() {
        Person person = null;
          try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ObjectOutputStream oos = new ObjectOutputStream(baos);
                  oos.writeObject(this);
        		// 将流序列化成对象
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bais);
                 person = (Person) ois.readObject();
              } catch (IOException e) {
                 e.printStackTrace();
              } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
         return person;
      }


    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.myclone();
        p2.setName("tom");
        address.setAddress("西安");

        System.out.println(p1);
        System.out.println(p2);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

贾扬清开源 AI 框架 Caffe | 开源英雄

【编者按】在开源与人工智能的灿烂星河里,贾扬清的名字都格外地耀眼。因为导师 Trevor Darrell 教授的一句“你是想多花时间写一篇大家估计不是很在意的毕业论文,还是写一个将来大家都会用的框架?”,学生贾扬清一头扎进了创 Caffe…

通过postgis空间库导入sql格式的矢量数据到arcgis中

1、在postgis中创建数据库 命名为test3 2、创建空间扩展 3、导入sql矢量文件 进入psql.exe目录中 进入dos命令框中 输入命令,其中host输入自己的主机ip,database为自己的数据库名称,数据路径修改为自己电脑上的路径,注意反斜杠 psql

毫米波雷达技术在自动驾驶中的关键作用:安全、精准、无可替代

自动驾驶技术正以前所未有的速度不断演进,而其中的关键之一就是毫米波雷达技术。作为自动驾驶系统中的核心感知器件之一,毫米波雷达在保障车辆安全、实现精准定位和应对复杂环境中发挥着不可替代的作用。本文将深入探讨毫米波雷达技术在自动驾驶中的关键…

移远EC600U-CN开发板 day01

1.官方文档快速上手,安装驱动,下载QPYcom QuecPython 快速入门 - QuecPython (quectel.com)https://python.quectel.com/doc/Getting_started/zh/index.html 注意: (1)打开开发板步骤 成功打开之后就可以连接开发板…

IDC发布2023H1CRM报告 ,纷享销客增长率稳居第一

近期,国际数据公司(IDC)发布了《IDC China Semiannual CRM SaaS Tracker 2023H1》数据报告,该报告详细分析了纷享销客和Salesforce等国内外CRM厂商的数据。根据报告数据显示,纷享销客2023年H1的增长速度依然保持近40%&…

万宾科技智能井盖,实现对井盖的监测

随着人工智能和物联网技术的不断变化,各种适用于市政府提高管理能力和公共服务水平的高科技产品不断更新。在道路基础设施建设过程中,智能井盖传感器的出现时刻保护着城市地下生命线,而且可以对地下水道井盖进行实时的监测并完成数据上传等工…

原来阿里字节大厂程序员的简历长这样!

1 前言 疫情过后,IT行业内卷就不说了,有很多小伙伴跟我咨询面试环节及简历上的事,都想在简历方面有些突出,博眼球。我发现大部分初、中级甚至高级程序员的简历逻辑都比较混乱,花里胡哨,没有突出重点&#x…

基于单片机的甲醛检测器设计

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、设计的主要内容二、系统硬件设计三、软件设计4.1 程序结构流程图原理图 四、结论五、 文章目录 概要 本文将要提…

响应式生活常识新闻博客资讯网站模板源码带后台

模板信息: 模板编号:30483 模板编码:UTF8 模板分类:博客、文章、资讯、其他 适合行业:博客类企业 模板介绍: 本模板自带eyoucms内核,无需再下载eyou系统,原创设计、手工书写DIVCSS&a…

世界互联网大会领先科技奖发布 百度知识增强大语言模型关键技术获奖

11月8日,2023年世界互联网大会乌镇峰会正式开幕,今年是乌镇峰会举办的第十年,本次峰会的主题为“建设包容、普惠、有韧性的数字世界——携手构建网络空间命运共同体”。 目录 百度知识增强大语言模型关键技术荣获“世界互联网大会领先科技奖”…

十分钟理解回归测试(Regression Testing)

回归测试是一个系统的质量控制过程,用于验证最近对软件的更改或更新是否无意中引入了新错误或对以前的功能方面产生了负面影响(比如你在家中安装了新的空调系统,发现虽然新的空调系统可以按预期工作,但是本来亮的等却不亮了&#…

应用在便携式多媒体播放器中的音频Codec芯片

便携式多媒体播放器(PMP,Portable Media Player),也就是通常人们所说的MP4。PMP的主要优点是:携带方便,能够直接播放高品质音/视频文件;也可以浏览图片,以及作为移动硬盘使用;此外,P…

无人机航拍技术基础入门,无人机拍摄的方法与技巧

一、教程描述 买了无人机,可是我不敢飞怎么办?禁飞区越来越多,到底哪儿才能飞?我的无人机跟你一样,为什么我拍不出大片?厂家的说明书看不进去,有没有一套无人机的课程,可以快速上手…

博阳精讯、凡得科技访问上海斯歌:共探BPM流程服务新高地

10月27日下午,来自博阳精讯、凡得科技的流程领域专家、领导一行参观访问了上海斯歌总部。三方举行了深度交流会谈,分享了彼此对流程领域的前沿洞察和技术实践,共同探索了BPM流程服务科技力与价值力的新高地。 本次研讨会上,博阳精…

高性能网络编程 - 解读5种I/O模型

文章目录 服务端处理网络请求流程图基础概念阻塞调用 vs 非阻塞调用同步处理 vs 异步处理阻塞、非阻塞 和 同步、异步的区别recvfrom 函数 五种I/O模型I/O模型1:阻塞式 I/O 模型(blocking I/O)I/O模型2:非阻塞式 I/O 模型(non-blocking I/O&a…

【Rust日报】2023-11-08 RustyVault -- 基于 rust 的现代秘密管理系统

RustyVault -- 基于 rust 的现代秘密管理系统 RustyVault 是一个用 Rust 编写的现代秘密管理系统。RustyVault 提供多种功能,支持多种场景,包括安全存储、云身份管理、秘密管理、Kubernetes 集成、PKI 基础设施、密码计算、传统密钥管理等。RustyVault 可…

基于MATLAB的关节型六轴机械臂轨迹规划仿真

笛卡尔空间下的轨迹规划,分为直线轨迹规划和圆弧轨迹规划,本文为笛卡尔空间下圆弧插值法的matlab仿真分析 目录 1 实验目的 2 实验内容 2.1标准D-H参数法 2.2实验中使用的Matlab函数 3 全部代码 4 仿真结果 1 实验目的 基于机器人学理论知识&…

C++二分查找算法:阶乘函数后 K 个零

涉及知识点 二分查找 数学 题目 f(x) 是 x! 末尾是 0 的数量。回想一下 x! 1 * 2 * 3 * … * x,且 0! 1 。 例如, f(3) 0 ,因为 3! 6 的末尾没有 0 ;而 f(11) 2 ,因为 11! 39916800 末端有 2 个 0 。 给定 k&a…

Go RabbitMQ简介 使用

RabbitMQ简介 RabbitMQ 是一个广泛使用的开源消息队列系统,它实现了高级消息队列协议(AMQP)标准,为分布式应用程序提供了强大的消息传递功能。RabbitMQ 是 Erlang 语言编写的,具有高度的可扩展性和可靠性,…

暴力递归转动态规划(十四)

题目 arr是面值数组,其中的值都是正数且没有重复。再给定一个正数aim。 每个值都认为是一种面值,且认为张数是无限的。 返回组成aim的最少货币数 暴力递归 依然是面值张数的问题,暴力递归尝试的过程是从数组arr index 0位置出发&#xff0c…