Cloneable接口和对象的克隆——浅拷贝和深拷贝

用Clonable接口实现对象的克隆——浅拷贝和深拷贝

  • 1. 浅拷贝
  • 2. 深拷贝

在Object类中提供了clone方法,用来是实现对象的克隆!

1. 浅拷贝

我们首先来尝试用clone方法去克隆一个Person对象

public class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person("zhangsan",10);System.out.println("person1: " + person1);Person person2 = (Person) person1.clone();}
}

这段代码会报错:
在这里插入图片描述
报错原因:
在这里插入图片描述

大概意思就是clone方法在Object类中是被protected修饰的,主类无法访问到clone方法。

我们打开Object类,找到clone方法,如下:
在这里插入图片描述
分析:被protected修饰的方法只能在同一个包或者不同包的子类中使用。在上述代码中,Person类继承了Object类,因此可以在Person类中去访问clone方法,而当想在Test类中通过person1去访问Person类继承下来的clone方法,这是不可行的!因为Test类是不同包的非子类,无法访问!

这可怎么办呀?
在这里插入图片描述

第一步: 可以在Person类中重写clone方法,这样就可以在同一包的Test类中去调用clone方法了!

快捷生成重写的clone方法:
在这里插入图片描述

生成了如下代码:

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

重写clone方法后,我们会发现依然会报错,查看报错结果:
在这里插入图片描述
意思就是有异常没有去处理

第二步: 我们发现,clone方法里有个异常声明,当去调用clone方法时,需要去处理异常,我们可以将其交给JVM处理,即在main方法处也进行声明!
在这里插入图片描述

显然,还是有报错,再看看有什么报错信息
在这里插入图片描述
Person类中的clone方法返回的是Object类,而去用一个Person类去接收,这是不可行的!向下转型需要进行强转!

第三步: 向下转型
在这里插入图片描述

这时,好像没有报错信息了欸,这时你嘴角开始微微上扬,仿佛看到了曙光!
在这里插入图片描述
这时,你开始运行你的代码
在这里插入图片描述

怎么又又又报错了?!坚持住!仔细来看报错信息,CloneNotSupportedException,就是不支持克隆的意思。

第四步: 解决办法:实现Cloneable接口
在这里插入图片描述

这时,运行就不会报错啦!就成功克隆了person1。

我们再来看看Cloneable接口:
在这里插入图片描述

打开后发现,怎么是个空接口嘞?这个空接口有什么用?
答:空接口也叫做标记接口,表示当前的类可以被克隆

这不就恰巧解决了刚刚不支持克隆的问题吗

最后奉上修改后的代码:

public class Person implements Cloneable{public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "{" +"name='" + name + '\'' +", age=" + age +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("zhangsan",10);System.out.println("person1: " + person1);Person person2 = (Person)person1.clone();System.out.println("person2: " + person2);}
}

2. 深拷贝

假如,在原来代码基础上,我们再创建一个money对象

class Money {public double money;public Money(double money) {this.money = money;}
}public class Person implements Cloneable{public String name;public int age;public Money m = new Money(9.9);public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", money=" + m.money +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("zhangsan",10);Person person2 = (Person)person1.clone();System.out.println("修改前person1: " + person1);System.out.println("修改前person2: " + person2);person2.m.money = 99.99;System.out.println("修改后person1: " + person1);System.out.println("修改后person2: " + person2);}
}

运行结果:
在这里插入图片描述
我们发现:在克隆person1对象后,修改person2中的money属性,本应该不会影响person1中money属性的值,但是运行结果却是影响了。究其根本根本就是浅拷贝导致的,下面来画图演示:
在这里插入图片描述

其中绿色表示拷贝后的,我们不难发现,拷贝person1时,只拷贝了person1的属性,而m对象里的money属性并没有进行拷贝。其中,在拷贝person1的属性m时,拷贝的是money的地址。所以,person1和person2的m属性所指是同一个money对象。这也就是为什么在修改person2中m的money属性时,person1中m的money属性也会变化。

那么该如何去解决这个问题呢?答案就是进行深拷贝,将m对象也进行克隆

class Money implements Cloneable{public double money;public Money(double money) {this.money = money;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class Person implements Cloneable{public String name;public int age;public Money m = new Money(9.9);public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", money=" + m.money +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp = (Person)super.clone();tmp.m = (Money)this.m.clone();//克隆money属性return tmp;}
}

在Money类中也实现Cloneable接口,重写clone方法;并修改Person类中的clone方法(仔细思考修改后的clone方法

这时,运行结果:
在这里插入图片描述
画图演示当前深拷贝:

在这里插入图片描述

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

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

相关文章

Perforce静态代码分析专家解读MISRA C++:2023®新标准:如何安全、高效地使用基于范围的for循环,防范未定义行为

MISRA C:2023——MISRA C 标准的下一个版本来了!为了帮助您了解 MISRA C:2023相比于之前版本的变化,我们将继续为您带来Perforce首席技术支持工程师Frank van den Beuken博士的博客系列,本期为第三篇。 在前两篇系列文…

企业为何需要搭建线上虚拟品牌展厅?

在数字化时代,线上虚拟品牌展厅已成为企业不可或缺的一部分。以下是构建线上虚拟品牌展厅的4大关键理由: 1、迎合在线购物趋势 随着移动互联网的飞速发展和普及,消费者越来越倾向于在线购物。一个线上虚拟品牌展厅能够完美地满足这一需求&am…

数据分析必备:一步步教你如何用matplotlib做数据可视化(5)

1、Matplotlib Multiplots 在本章中,我们将学习如何在同一画布上创建多个子图。 subplot()函数返回给定网格位置的axes对象。此函数的签名是 plt.subplot(subplot(nrows, ncols, index)在当前图中,该函数创建并返回一个Axes对象,在ncolsaxe…

VScode如何调试

调试 1.打断点 1.点击调试按钮 3.点击下拉选择环境node,点击绿三角选择输入调试的命令(具体命令查看package.json中scripts中的哪一个命令和运行的文件),点击右边的设置(可以直接跳下面第八步!&#xff…

EOS Black灵魂回响黑色账号注册 EOS Black怎么注册账号教程

又一款新的MMORPG游戏即将上线,游戏名称叫做《灵魂回响:黑色》,游戏继承了《灵魂回响》系列的基本世界观和背景故事,从危险中救出来的阿尔卡纳们沉醉于权力开始堕落, 少数阿尔卡纳还没有忘记自己的本分,为净化世界而努力&#xff…

[大模型]MiniCPM-2B-chat WebDemo部署

MiniCPM-2B-chat 介绍 MiniCPM 是面壁智能与清华大学自然语言处理实验室共同开源的系列端侧大模型,主体语言模型 MiniCPM-2B 仅有 24亿(2.4B)的非词嵌入参数量。 经过 SFT 后,MiniCPM 在公开综合性评测集上,MiniCPM …

124M中国十大城市群规划范围数据

城市群是由若干个都市圈构成的广域城镇化形态,其内部应该包含若干个中心城市。 都市圈是指围绕某一个中心城市,即超大或特大城市的城镇化形态。 无论在体量还是在层级上,都市圈要低于城市群的概念。 现在,我们就来为你分享一下…

不入耳的蓝牙耳机平价推荐,五大爆款分析测评

开放式耳机在如今社会中已经迅速成为大家购买耳机的新趋势。它作为骨传导耳机,深受用户的喜爱,不仅可以随时感知周围环境,还提供了高质量的音效体验,对于热爱运动的人士而言,高品质的骨传导耳机无疑是首选。同时&#…

Spring是如何设计IOC容器的?BeanFactory ApplicationContext

BeanFactory是Spring框架中最底层的接口,用于实例化、配置和管理bean。它使用控制反转(IOC)模式,将对象的创建、管理和装配的职责从应用程序代码中转移给Spring容器。这样,应用程序代码就无需关心对象如何创建和装配&a…

卡本医疗VENUS登陆香港国际医疗展,探索全球医疗发展新机遇

由香港贸易发展局主办的第15届香港国际医疗及保健展、以及联合香港特别行政区政府举办的第四届亚洲医疗健康高峰论坛在中国香港圆满落幕。 香港国际医疗及保健展是亚太地区最具影响力的B2B医疗贸易展览会之一,辐射海内外市场,本次邀请了超过8500家买家以…

模型部署onnx入门

一、定义 1.定义 2. 环境安装 3. 案例 4. 可视化界面 5. 参考网址 6. 推理引擎 onnx Runtime 进行单张图片推理,本地部署 7. 推理引擎onnx Runtime 进行单张图片推理,调用摄像头获取画面 8. 推理引擎onnx Runtime 进行图片推理,调用摄像头获…

美国原装二手KEITHELY2410替代新品keithley2470数字源表

Keithley 2470 高压 SourceMeter 源测量单元 (SMU) 仪器将先进的 Touch, Test, Invent 技术带到您的指尖。它将创新的图形用户界面 (GUI) 与电容式触摸屏技术相结合,使测试变得直观,并最大限度地缩短学习曲线,帮助工程师和科学家更快地学习、…

【字符串解析】IP地址字段解析提取函数接口

在嵌入式业务逻辑中,我们有时需要从配置文件、串口或者服务端接收的消息数据中进行字符串解析,来提取需要的目标字符串字段。通常我们会调用字符串处理相关的函数,例如strstr,strchr,sscanf等,再结合指针偏…

数据驱动决策:工单统计工具如何赋能企业精准运营

在当今这个数字化飞速发展的时代,企业对于内部运营效率的追求已经达到了前所未有的高度。你是否曾为了繁杂的工单统计管理而头疼不已?是否曾因为无法准确进行工单统计数据而错失商机?今天,我将向你展示一款革命性的工单统计工具&a…

MBR40100CT-ASEMI无人机专用MBR40100CT

编辑:ll MBR40100CT-ASEMI无人机专用MBR40100CT 型号:MBR40100CT 品牌:ASEMI 封装:TO-220 最大平均正向电流(IF):40A 最大循环峰值反向电压(VRRM):100V…

【数据分析】线性及逻辑回归模型和Python实现

各位大佬好 ,这里是阿川的博客,祝您变得更强 个人主页:在线OJ的阿川 大佬的支持和鼓励,将是我成长路上最大的动力 阿川水平有限,如有错误,欢迎大佬指正 Python 初阶 Python–语言基础与由来介绍 Python–…

冒泡排序、选择排序

冒泡排序 按照冒泡排序的思想,我们要把相邻的元素两两比较,当一个元素大于右侧相元素时,交换它们的位置;当一个元素小于或等于右侧相邻元素时,位置不变 大的往右丢(往下沉),小的往…

移动应用开发大作业报告

1 基本信息 1.1 系统名称 中华字典 1.2 开发运行环境 开发环境:Windows 10 专业版,JDK 1.8,AndroidStudio 运行环境:Java SE Runtime Environment (JRE) 8 1.3 使用的核心技术 JFrame:作为实现界面的窗体类&…

【数据结构与算法】最小生成树

文章目录 最小生成树(MST)定义 构造最小生成树Prim算法Kruskal算法 最小生成树(MST) 连通图的生成树包含图的所有顶点,并且只含有尽可能少的边。对于生成树来说,若砍去它的一条边,则会使生成树…

练习时长 1 年 2 个月的 Java 菜鸡练习生最近面经,期望25K

面经哥只做互联网社招面试经历分享,关注我,每日推送精选面经,面试前,先找面经哥 自我介绍:本人是练习时长 1 年 2 个月的 Java 后端菜鸡练习生。下面是我最近面试的面经: 百度 一面 约1h时间:2…