当前位置: 首页 > news >正文

Java中的深拷贝和浅拷贝

目录

🍎引出拷贝

🍎浅拷贝

🍎深拷贝

🍎总结


引出拷贝

现在有一个学生类和书包类,在学生类中有引用类型的书包变量:

class SchoolBag {private String brand;   //书包的品牌private int size;   //书包的尺寸//getter、setter略public SchoolBag(String brand, int size) {this.brand = brand;this.size = size;}@Overridepublic String toString() {return "SchoolBag{" +"brand='" + brand + '\'' +", size=" + size +'}';}
}class Student {private String name;private int age;private SchoolBag schoolBag;public Student(String name, int age, SchoolBag schoolBag) {this.name = name;this.age = age;this.schoolBag = schoolBag;}//getter、setter略@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", schoolBag=" + schoolBag +'}';}
}

创建一个学生对象,现在想在内存中拷贝一份和这个学生对象指向的对象相同的对象,那么应该怎么去做呢?

可能我们会像下边这样写:

...
Student stu1 = new Student("张华",18,new SchoolBag("小米",4));
//直接创建一个新的引用指向这个stu1指向的对象
Student stu2 = stu1;

这显然是错误的,这从内存的分布上就可以知道,stu1与stu2虽然是两个不同的引用变量,但是指向的是堆内存中的同一块空间或者说指向的是同一个对象,并没有真正实现克隆的效果。它们两个引用和引用对象在内存中的关系如图

那么要怎么实现对象内存的拷贝呢?


浅拷贝

 我们可以通过使用Java中的clone方法,该clone方法是Object类中定义的,因此我们只需要在自己的类中重写这个方法,就可以实现对象的拷贝。但是clone方法的使用,并不只是单纯的重写就可以实现效果的,下面我们依次来看:

1.待克隆对象所在类重写clone方法

class Student {private String name;private int age;private SchoolBag schoolBag;public Student(String name, int age, SchoolBag schoolBag) {this.name = name;this.age = age;this.schoolBag = schoolBag;}//getter、setter略@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", schoolBag=" + schoolBag +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

调用重写的clone方法,克隆对象,会发现,报错了:

哦😂,原来还得让待克隆对象所在类实现Cloneable接口,但是当我们查看这个接口的内容时,却发现这是一个空接口:

为什么是一个空接口呢?

这里可以记作它是一个标记接口,实现Cloneable接口的类被标记为可以被clone的类。

现在我们让Student类实现Cloneable接口再试试看能不能克隆成功。

2.实现Cloneable接口

class Student implements Cloneable{private String name;private int age;private SchoolBag schoolBag;public Student(String name, int age, SchoolBag schoolBag) {this.name = name;this.age = age;this.schoolBag = schoolBag;}//getter、setter略@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", schoolBag=" + schoolBag +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

现在再次尝试clone,嗯...又报错了......

原来时异常,我们把异常抛给JVM一下:

 啊,还报错...

原来是clone方法的返回类型时Object:

 我们进行向下转型,然后进行克隆输出会发现克隆成功了

 现在克隆出来的对象以及原型在内存中因该是这样分布的:

当我们修改stu1对象中的schoolbag成员变量后再进行对象的输出,会发现stuClone对象的schoolbag中的值也发生了变化,这是为什么?????

 这是因为clone出来的stuClone对象和stu1对象的引用成员变量schoolbag指向的还是同一片内存空间,二者还是共享这一片内存空间。
 

因此我们可以得到何为浅拷贝?

当引用变量指向的对象中还包含引用变量时,如果只对当前的外部的引用变量进行clone,克隆出来对象的基本数据类型都会被正常拷贝;而内部的引用变量只是将引用的值clone给了另一个clone对象的引用,因此无法在真正意义上实现对象的拷贝,下面我们来解决这种clone后仍存在成员变量有内存共享的问题。


深拷贝

既然clone方法能够实现对对象的拷贝,那么我们在引用变量内部的引用变量身上再使用一次clone方法不就可以解决这种浅拷贝问题了吗?

现在我们进行上述操作,让SchoolBag类重写clone方法并且实现标记接口Cloneable:

class SchoolBag implements Cloneable{private String brand;   //书包的品牌private int size;   //书包的尺寸//getter、setter略public SchoolBag(String brand, int size) {this.brand = brand;this.size = size;}@Overridepublic String toString() {return "SchoolBag{" +"brand='" + brand + '\'' +", size=" + size +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

在对Student对象进行克隆是也对其中的引用成员变量进行克隆,我们只需要在Student类的clone方法中这样写就可以了:

class Student {...@Overrideprotected Object clone() throws CloneNotSupportedException {Student stuClone = (Student)super.clone();SchoolBag schoolbagClone = (SchoolBag) this.schoolBag.clone();stuClone.setSchoolBag(schoolbagClone);return stuClone;}...
}

现在我们在进行stu对象的schoolbag修改后的输出,会发现stu1对象的修改已经不会影响stuClone对象了,二者之间已经没有共享的存储空间了:

 此时这两个对象的内存布局图如下:

 因此我们可以得到何为深拷贝?

深拷贝进行后,进行拷贝的对象与拷贝出来的对象之间没有共享的一片存储空间,二者独立存在,对其中任何一方的修改都不会影响另外一方。


总结

拷贝实现方法clone的使用步骤以及注意事项:

  1. 实现Cloneable标记接口重写Object类中的clone方法
  2. 捕获处理或抛出使用clone方法带来的异常
  3. 将克隆猴返回的Object类型的对象向下转型为克隆类型
  4. 如果克隆对象的内部还有引用类型,则需要对内部的引用类型也按照上述1,2,3步骤在自己的clone方法中进行克隆返回。

相关文章:

Java中的深拷贝和浅拷贝

目录 🍎引出拷贝 🍎浅拷贝 🍎深拷贝 🍎总结 引出拷贝 现在有一个学生类和书包类,在学生类中有引用类型的书包变量: class SchoolBag {private String brand; //书包的品牌private int size; //书…...

大文件上传

上图就是大致的流程一、标题图片上传课程的标题图片Ajax发送请求到后端后端接收到图片使用IO流去保存图片,返回图片的信息对象JS回调函数接收对象通过$("元素id").val(值),方式给页面form表达img标签src属性值,达到上传图片并回显二…...

Python每日一练(20230327)

目录 1. 最大矩形 🌟🌟🌟 2. 反转链表 II 🌟🌟 3. 单词接龙 II 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日…...

Centos7 升级内核到5.10mellanox 编译安装

升级5.10内核 #uname -r 重启后 进入新的内核 进入新的内核信息 直接查看是看不到gcc版本 5.10需要高版本gcc 才可以进行编译...

冯诺依曼,操作系统以及进程概念

文章目录一.冯诺依曼体系结构二.操作系统(operator system)三.系统调用和库函数四.进程1.进程控制块(PCB)2.查看进程3.系统相关的调用4.fork介绍(并发引入)五.总结一.冯诺依曼体系结构 计算机大体可以说是…...

7.网络爬虫—正则表达式详讲

7.网络爬虫—正则表达式详讲与实战Python 正则表达式re.match() 函数re.search方法re.match与re.search的区别re.compile 函数检索和替换检索:替换:findallre.finditerre.split正则表达式模式常见的字符类正则模式正则表达式模式量词正则表达式举例前言&…...

关于位运算的巧妙性:小乖,你真的明白吗?

一.位运算的概念什么是位运算?程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。位运算就是直接操作二进制数,那么有哪些种类的位运算呢?常见的运算符有与(&)、或(|)、异或(^)、…...

【Android车载系列】第5章 AOSP开发环境配置

1 硬件支持 建议空闲内存16G以上,同时硬盘400G以上 内存不够可以使用 Linux 的交换分区2 VMware Workstation安装 https://download3.vmware.com/software/wkst/file/VMware-workstation-full-16.1.1-17801498.exe2.1 Ubuntu镜像 http://mirrors.aliyun.com/ubun…...

个人时间管理网站—Git项目管理

🌟所属专栏:献给榕榕🐔作者简介:rchjr——五带信管菜只因一枚😮前言:该专栏系为女友准备的,里面会不定时发一些讨好她的技术作品,感兴趣的小伙伴可以关注一下~👉文章简介…...

2023最新ChatGPT整理的40道Java高级面试题

2023 年最火的就是 ChatGPT 了,很多同事使用他完成一些代码上的智能提示,也有人使用它发了财《「用ChatGPT年入百万!」各博主发布生财之道,网友:答辩搬运工》、《“躺着就能赚大钱”?ChatGPT火了,有人早就动起坏脑筋》等。 最近我也使用 ChatGPT 写技术文章了,比如:《…...

单机分布式一体化是什么?真的是数据库的未来吗,OceanBase或将开启新的里程碑

一. 数据 我们先说说数据这个东西,这段时间的ChatGPT在全世界的爆火说明了一件事,数据是有用的,并且大量的数据如果有一个合适的LLM大规模语言模型训练之后,可以很高程度的完成很多意想不到的事情。 我们大多数的时候的注意力只…...

100天精通Python丨基础知识篇 —— 03、Python基础知识扫盲(第一个Python程序,13个小知识点)

文章目录🐜 1、Python 初体验Pycharm 第一个程序交互式编程第一个程序🐞 2、Python 引号🐔 3、Python 注释🦅 4、Python 保留字符🐯 5、Python 行和缩进🐨 6、Python 空行🐹 7、Python 输出&…...

springboot逍遥大药房管理系统

084-springboot逍遥大药房管理系统演示录像开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包&a…...

ZYNQ中的GPIO与AXI GPIO

GPIO GPIO—一种外设,对器件进行观测和控制MIO—将来自PS外设和静态存储器接口的访问多路复用到PS引脚上处理器控制外设的方法—通过一组寄存器包括状态寄存器和控制寄存器,这些寄存器都是有地址的,通过这些寄存器的读写进行外设的控制sessi…...

接口导入功能

1.接口api export function import(param) { return fetch({ url: XXX.import, method: POST, headers: { Content-Type: multipart/form-data; }, data: param }) } 2.页面vue 和 js逻辑 <el-button :loading"disable&qu…...

网络安全知识点总结 期末总结

1、信息安全从总体上可以分成5个层次&#xff0c;密码技术 是信息安全中研究的关键点。 2、握手协议 用于客户机与服务器建立起安全连接之前交换一系列信息的安全信道。 3、仅设立防火墙系统&#xff0c;而没有 安全策略 &#xff0c;防火墙就形同虚设。 4、应用代理防火墙 …...

linux挂载远程目录

服务端操作 # 1、安装NFS程序 yum -y install nfs* rpcbind,在centos6以前自带的yum源中为portmap。 使用yum安装nfs时会下载依赖&#xff0c;因此只要下载nfs即可&#xff0c;无需再下载rpcbind. # 2、查看是否安装了nfs与rpcbind rpm -qa | grep nfs rpm -qa | grep rpc…...

ChatGPT—初识

ChatGPT初识 由于ChatGPT 注册相关的文章被平台限制了&#xff0c;所以有注册相关的问题可以私聊&#xff0c;或者可以代注册 Chat GPT是一款基于GPT模型的对话型AI模型&#xff0c;能够模拟真实的对话风格和行为方式&#xff0c;让人与AI的交互变得更加自然顺畅。下面将从Chat…...

【ArcGIS Pro二次开发】(18):地理处理工具类【Geoprocessing】补遗

ArcGIS Pro SDK 3.0中的Geoprocessing类是用于执行地理处理工具的核心类。地理处理工具是用于执行空间分析、数据转换、数据管理等任务的工具集&#xff0c;包括常见的空间分析工具、栅格处理工具、矢量处理工具、地图制图工具等。 之前有简单记录了下Geoprocessing工具的用法…...

国产芯片方案——红外测温体温计方案

红外测温体温计采用了热电堆式&#xff0c;利用塞贝克效应&#xff0c;将收集到的红外线光信号转化为电信号&#xff0c;再经过放大等处理&#xff0c;按内部的算法校正后再显示屏幕上输出具体温度值&#xff0c;能快速准确地测量人体体温。红外测温体温计广泛应用于医疗卫生、…...

详解ChatGPT的免费总结插件Glarity

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,科大讯飞比赛第三名,CCF比赛第四名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…...

RK3588平台开发系列讲解(NPU篇)NPU调试方法

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、日志等级二、NPU 支持查询设置项沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们一起来看一下NPU的调试方法。 一、日志等级 NPU 的运行库会根据开发板上的系统环境变量输出一些日志信息或者生成…...

基于微信小程序+爬虫制作一个表情包小程序

跟朋友聊天斗图失败气急败坏的我选择直接制作一个爬虫表情包小程序&#xff0c;从源头解决问题&#xff0c;从此再也不用担心在斗图中落入下风 精彩专栏持续更新↓↓↓ 微信小程序实战开发专栏 一、API1.1 项目创建1.2 图片爬虫帮助类1.3 测试窗体1.4 接口封装二、小程序2.1 项…...

TS常用数据类型(TypeScript常用数据类型,ts常用数据类型和js常用数据类型的区别)

简述&#xff1a;TS全称TypeScript&#xff0c;是一门弱类型的语言&#xff0c;可以理解为是 JavaScript 的扩展语法&#xff0c;因此我们可以在 ts 中继续写js代码&#xff0c;且不会报错&#xff0c;而且TypeScript 又叫做静态的JavaScript&#xff0c;可称为静态类型语言&am…...

关于Numpy的特殊符号@和矩阵运算

符号之谜 在Numpy中&#xff0c;看到了符号&#xff0c;但是无论是google搜索或者baidu搜索&#xff0c;由于符号是一个特殊字符&#xff0c;所以很难检索到答案。 其实很简单&#xff0c;他就是Numpy库中的一个操作符&#xff0c;在numpy库的说明中&#xff0c;落在numpy.mat…...

动态版通讯录——“C”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是动态版通讯录啦&#xff0c;其实之前&#xff0c;我就已经写过静态版的通讯录了&#xff0c;只是存在着一些问题&#xff0c;具体细节可以详细看看我的静态版通讯录&#xff0c;好了&#xff0c;话不多说&…...

SpringBoot 将PDF转成图片或World

SpringBoot 将PDF转成图片或World 准备工作Apache PDFBox将PDF转成一张图片将PDF转成多张图片将PDF转成其他文件格式总结SpringBoot 是一款非常流行的 Java Web 开发框架,可以用来构建各种 Web 应用程序。在本篇博客中,我们将介绍如何使用 SpringBoot 将 PDF 转换成图片或其他…...

JavaScript中的for in和for of的区别(js的for循环)

简述&#xff1a;js中的for循环大家都知道&#xff0c;今天来分享下for in和for of在使用时区别和注意事项&#xff0c;顺便做个笔记&#xff1b; 测试数据 //数组const arr [1, 2, 3, 4, 5]//对象const obj {name: "小李",color: ["plum", "pink&q…...

C++的各种初始化

C的各种初始化 1.默认初始化 默认初始化是指定义变量时没有指定初值时进行的初始化操作。例如int a; Sales_data myData;等等。这些变量被定义了而不是仅仅被声明&#xff08;因为没有extern关键字修饰&#xff09;&#xff0c;而且没有显式的赋予初值。特别的&#xff0c;如…...

使用Python突破某网游游戏JS加密限制,进行逆向解密,实现自动登录

兄弟们天天看基础看腻了吧 今天来分享一下如何使用Python突破某网游游戏JS加密限制&#xff0c;进行逆向解密&#xff0c;实现自动登录。 逆向目标 目标&#xff1a;某 7 网游登录主页&#xff1a;aHR0cHM6Ly93d3cuMzcuY29tLw接口&#xff1a;aHR0cHM6Ly9teS4zNy5jb20vYXBpL…...

单位网站建设/国外十大免费服务器和域名

1.8 GloVe 词向量 共现矩阵X 1.9 情绪分类 简单情绪分类模型 情绪分类RNN模型 1.10 词嵌入除偏 词嵌入中的偏见问题...

广州制作网站公司/宁波seo外包费用

【回复“1024”&#xff0c;送你一个特别推送】在 Google I/O 2018 开发者大会上&#xff0c;谷歌官方推出了 Android Jetpack&#xff0c;其中包含的 Android 开发架构组件能够帮助我们简化开发流程&#xff0c;从而轻松打造出优质应用。开发者能够利用 Jetpack 组件学习最佳实…...

洛阳网站建设多少钱/app推广平台排行榜

最最简单的数据结构&#xff0c;数据结构入门必备&#xff0c;新手必备顺序表! 目录本节目标1.线性表概念顺序表实现静态顺序表动态顺序表接口实现本节目标 了解线性表结构能够自己实现顺序表顺序表oj题 1.线性表概念 1线性表线性表&#xff08;linear list&#xff09; 是…...

wordpress插件连不上/网站策划运营

培训主题 消费系统培训 消费机功能基本操作介绍 CM20集消费机 出纳机 补贴机功能于一体 机器的操作 分为机器操作和软件操作两大块 其中可以通过机器操作来实现消费机 出纳机 补贴机之间的切换 软件界面简洁清晰 操作方便 功能齐全 系统稳定可靠 大大提升了管理效率 机器硬件核…...

安监局 政府网站建设和管理/域名解析网站

RPG/400中有两种数值型数据相对应&#xff0c;一种是ZONED DECIMAL&#xff0c; 另一种是PACKED DECIMAL。 它们虽然都可以存放数值型数据&#xff0c;但是它们所占用的存储空间是不一样大的。ZONED DECIMAL用一个BYTE存放一个数字&#xff0c;而PACKED DECIMAL用一个BYTE存放…...

discuz可以做商城网站吗/百度下载正版

本文实例讲述了Python多线程及其基本使用方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a; 1.Python中的多线程 执行一个程序&#xff0c;即在操作系统中开启了一个进程&#xff0c;在某一时刻&#xff0c;一个CPU内核只能进行一个进程的任务&#xff0c;现在的计算…...