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.rhkb.cn/news/352973.html

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

相关文章

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

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

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

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

一个按钮更改Notes字体大小

大家好,才是真的好。 在说到正文以前,我们还是提两句,上周HCL发布了Notes/Domino 12.0.2FP4补丁,以及在亚马逊云应用市场上架了HCL Domino 14.0。 现在谈谈正文部分。 随着岁月飞逝,使用Notes的人也开始日渐眼花&a…

基于WPF技术的换热站智能监控系统17--项目总结

1、项目颜值,你打几分? 基于WPF技术的换热站智能监控系统01--项目创建-CSDN博客 基于WPF技术的换热站智能监控系统02--标题栏实现-CSDN博客 基于WPF技术的换热站智能监控系统03--实现左侧加载动画_wpf控制系统-CSDN博客 基于WPF技术的换热站智能监…

AI时代的数据治理:挑战与策略

随着人工智能(AI)技术的突飞猛进,我们已迈进智能时代的大门。在这个新时代里,数据无疑成为推动AI创新与进步的核心力量。然而,与此同时,数据治理的紧迫性也日益凸显,它成为确保AI系统有效、公正…

Nginx实战:故障处理_后端服务正常,nginx偶发502(Bad Gateway)

一、故障场景 用户访问服务偶发报错【502 Bad Gateway】,但是服务后端正常运行。架构如下: #mermaid-svg-4dDszusKEuPgIPlt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4dDszusKEuPgIPlt…

mysql8.x安装教程,window版本

mysql8.x安装教程,window版本 1. 安装步骤 1. 安装步骤 下载暗安装包,https://dev.mysql.com/downloads/file/?id528489 双击安装包,然后按照下述步骤操作 选择custom,然后点击next 如图选中,mysql server和mysq…

vuex computed获取mapGetters,字典的值不能实时更新

实际原因,深浅拷贝的问题 字典dicts中包含很多类型字典,是个object,原来代码 修改后代码 computed中通过mapGetters获取

计算机网络5:运输层

概述 进程间基于网络的通信 计算机网络中实际进行通信的真正实体,是位于通信两端主机中的进程。 如何为运行在不同主机上的应用进程提供直接的逻辑通信服务,就是运输层的主要任务。运输层协议又称为端到端协议。 运输层向应用层实体屏蔽了下面网络核心…

视频太大了怎么缩小内存

我们在分享视频的时候,有时候会遇到过视频文件太大,无法发送或者上传的情况,别担心,今天我就来给大家分享一个简单有效的方法,让你的视频变得更小,更方便分享! 打开 “51视频处理官网 的网站。上…

msvcp100.dll已加载但找不到入口点的处理方法,分析比较靠谱的msvcp100.dll解决方法

用户在日常使用中有时会遇到一个错误提示:“已加载 msvcp100.dll,但找不到入口点”。这一信息不仅引发了使用上的不便,也对软件的稳定性产生了质疑。理解并解决该问题不仅对确保计算机正常运行至关重要,也对维护软件的长期稳定性和…

【微信小程序开发实战项目】——如何去申请腾讯地图账号和在微信公众平台,配置request路径和添加地图插件

👨‍💻个人主页:开发者-曼亿点 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 曼亿点 原创 👨‍💻 收录于专栏&#xff1a…

【Java】已解决Java中的com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决Java中的com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException异常 在Java中操作MySQL数据库时,我们经常会使用JDBC(Java Database Connectivi…

【x264】整体框架汇总

【x264】整体框架汇总 1. x264整体框架图2. 思考 参考: x264源代码简单分析:概述 参数分析: 【x264】x264编码器参数配置 流程分析: 【x264】x264编码主流程简单分析 【x264】编码核心函数(x264_encoder_encode&…

集体爆雷!突发中科院2区(Top) 被标记!新增10本期刊被“On Hold“

本周投稿推荐 SSCI • 中科院2区,6.0-7.0(录用友好) EI • 各领域沾边均可(2天录用) CNKI • 7天录用-检索(急录友好) SCI&EI • 4区生物医学类,0.5-1.0(录用…

springboot优雅shutdown时如何保障异步线程的安全

我前面写了一篇springboot优雅shutdown的文章,看起来一切很美好。 https://blog.csdn.net/chenshm/article/details/139640775 那是因为没有进行多线程测试。如果一个请求中包括阻塞线程(主线程)和非阻塞线程(异步线程&#xff09…

uniapp滚动加载

uniapp实现滚动加载,先获取10条数据,滚动到底时,再获取10条数据,以此类推,直至没有数据为止。 使用scroll-view,注意一定要给一个固定高度,隐藏滚动条会更美观 2. 在data中定义 3. 获取数据 …

Minecraft模组开发(fabric)之准备工作

Minecraft模组开发(fabric)之准备工作 最近心血来潮想开发个Minecraft的模组,一边学习一边开发,顺带着将一些步骤、学习心得整理下来。之所以选择fabric,是因为自己的光影包使用的是iris-fabric,所以就想着…

欢乐钓鱼大师游戏攻略:萌新必备攻略大全!钓鱼脚本!

《欢乐钓鱼大师》是一款休闲益智类游戏,以钓鱼为主题,玩家需要通过各种钓鱼任务和挑战,收集不同种类的鱼类,并提升自己的钓鱼技术和装备。本文将为大家详细解析游戏的各个方面,帮助玩家更好地掌握游戏技巧,…

【JS重点19】this指向问题总结

目录 一:普通函数this指向 普通函数在严格模式下: 二:箭头函数this指向 this指向说明 不适用this情况 三:改变this指向 1 call() 语法格式: 作用: 2 apply() 语法格式: 作用&#x…