java中clone方法的理解(深拷贝、浅拷贝)

文章目录

      • 前言:
      • 知识点一:什么是浅拷贝?
      • 知识点二:什么是深拷贝?
      • 知识点三、java拷贝(clone)的前提:
      • 知识点四:浅拷贝案例:
        • 拷贝类:
        • 测试类:
        • 总结:
        • 下面通过画图示意:
      • 知识点五:深拷贝案例:
        • 结果为:
        • 总结:
        • 画图说明:
      • 知识点六:总结

前言:

java中的clone一直是一个老生常谈的问题,另外关于克隆网上也有很多的写过这方面的问题。
我在这里记录一下我遇到的问题和使用clone的方法。

知识点一:什么是浅拷贝?

	我们这里说的浅拷贝是指我们拷贝出来的对象内部的引用类型变量和原来对象内部引用类型变量是同一引用(指向同一对象)。但是我们拷贝出来的对象和新对象不是同一对象。简单来说,新(拷贝产生)、旧(元对象)对象不同,但是内部如果有引用类型的变量,新、旧对象引用的都是同一引用。

知识点二:什么是深拷贝?

深拷贝:全部拷贝原对象的内容,包括内存的引用类型也进行拷贝

知识点三、java拷贝(clone)的前提:

1.首先我们需要知道Object类中一个clone()的方法,并且是protected关键字修饰的本地方法(使用native关键字修饰),我们完成克隆需要重写该方法。
注意:按照惯例重写的时候一个要将protected修饰符修改为public,这是JDK所推荐的做法,但是我测试了一下,
复写的时候不修改为public也是能够完成拷贝的。但是还是推荐写成public2.我们重写的clone方法一个要实现Cloneable接口。虽然这个接口并没有什么方法,但是必须实现该标志接口。
如果不实现将会在运行期间抛出:CloneNotSupportedException异常3.Object中本地clone()方法,默认是浅拷贝

知识点四:浅拷贝案例:

拷贝类:

package cn.cupcat.java8;public class Person implements Cloneable{private String name;private int age;private int[] ints;public int[] getInts() {return ints;}public Person(String name, int age, int[] ints) {this.name = name;this.age = age;this.ints = ints;}public void setInts(int[] ints) {this.ints = ints;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person(String name, int age) {this.name = name;this.age = age;}/***  默认实现* */@Overridepublic Object clone() throws CloneNotSupportedException {return  super.clone();}
}

测试类:

package cn.cupcat.java8;import org.junit.Test;public class CloneTest  {@Testpublic void test() throws CloneNotSupportedException {int[] ints = {1,2,3};String name = "zhangxiangyang";int age = 23;Person person = new Person("zhangxiangyang",age,ints);System.out.print("一:克隆前:  age = "+ age + "... name = "+ name + " 数组:");for (int i : ints){System.out.print(i + " ");}System.out.println();//拷贝Person clonePerson = (Person) person.clone();int clonePersonAge = clonePerson.getAge();String clonePersonName = clonePerson.getName();int[] ints1 = clonePerson.getInts();System.out.print("二:克隆后: age = "+ clonePersonAge + "... name = "+ clonePersonName + " 数组: ");for (int i : ints1){System.out.print(i + " ");}System.out.println();//修改:ints1[0] = 50;//修饰clonePerson.setName("666666666");age = person.getAge();name = person.getName();System.out.println();System.out.print("三:修改后原对象: age = "+ age + "... name = "+ name + "数组 ");for (int i : ints){System.out.print(i + " ");}System.out.println();System.out.println("四:person == clonePerson ? "+ (person == clonePerson ));}
}

结果为:

一:克隆前:  age = 23... name = zhangxiangyang 数组:1 2 3 
二:克隆后: age = 23... name = zhangxiangyang 数组: 1 2 3 三:修改后原对象: age = 23... name = zhangxiangyang数组 50 2 3 
四:person == clonePerson ? false

总结:

1.通过四输出  person == clonePerson ? false 可以看出,克隆以后的对象已经和以前不是同一对象了。因为其引用是不同的。
2.通过分析一、二可以看出我们的拷贝成功执行了,并且拷贝的数据也都正确
3.通过分析三,我们修改了拷贝后对象的name、intsints1[0] = 50;//修饰clonePerson.setName("666666666");发现原对象中的ints也跟着修改了,因此可以证明拷贝后的对象和原对象的ints数组指向了同一引用。而我们发现同时也修改了拷贝对象name属性,为什么那么原对象中的name属性没有发生改变呢?而且String类型也是引用类型呀? 别急,下面我会画图示意。
4. 通过以上总结,我们得出结论:clone()方法的默认实现是浅拷贝       

下面通过画图示意:

拷贝成功后:
这里写图片描述

修改拷贝对象过后:
这里写图片描述

ps:如果看不清楚图片,可以在标签窗口打开

知识点五:深拷贝案例:

该类只和浅拷贝在clone方法的实现上有区别,其他地方相同:

package cn.cupcat.java8;public class Person implements Cloneable{private String name;private int age;private int[] ints;public int[] getInts() {return ints;}public Person(String name, int age, int[] ints) {this.name = name;this.age = age;this.ints = ints;}public void setInts(int[] ints) {this.ints = ints;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Person(String name, int age) {this.name = name;this.age = age;}/***  深拷贝* */@Overridepublic Object clone() throws CloneNotSupportedException {Person person = new Person(name,age);int[] ints = new int[this.ints.length];System.arraycopy(this.ints,0,ints,0,ints.length);person.setInts(ints);return  person;}
}

该测试类和前拷贝测试类相同:

package cn.cupcat.java8;import org.junit.Test;public class CloneTest  {@Testpublic void test() throws CloneNotSupportedException {int[] ints = {1,2,3};String name = "zhangxiangyang";int age = 23;Person person = new Person("zhangxiangyang",age,ints);System.out.print("克隆前:  age = "+ age + "... name = "+ name + " 数组:");for (int i : ints){System.out.print(i + " ");}System.out.println();//拷贝Person clonePerson = (Person) person.clone();int clonePersonAge = clonePerson.getAge();String clonePersonName = clonePerson.getName();int[] ints1 = clonePerson.getInts();System.out.print("克隆后: age = "+ clonePersonAge + "... name = "+ clonePersonName + " 数组: ");for (int i : ints1){System.out.print(i + " ");}System.out.println();//修改:ints1[0] = 50;//修饰可控后的对象clonePerson.setName("666666666");age = person.getAge();name = person.getName();System.out.println();System.out.print("修改后原对象: age = "+ age + "... name = "+ name + "数组 ");for (int i : ints){System.out.print(i + " ");}System.out.println();System.out.println("person == clonePerson ? "+ (person == clonePerson ));}
}

结果为:

一:克隆前:  age = 23... name = zhangxiangyang 数组:1 2 3 
二:克隆后: age = 23... name = zhangxiangyang 数组: 1 2 3 三:修改后原对象: age = 23... name = zhangxiangyang数组 1 2 3 
四:person == clonePerson ? false

总结:

1.通过四可以看出完成了拷贝,并且克隆对象和原对象不是同一对象(没有同一引用)
2.通过一、二可以看出完成了拷贝并且数据正确
3.通过三,我们修改克隆以后的对象,打印原对象发现没有影响到原对象的数据,也就是说完成的深拷贝下面使用图解说明一下

画图说明:

拷贝完成后:
这里写图片描述

修改拷贝后对象后:

这里写图片描述

知识点六:总结

拷贝也算是我们经常使用的一个方法,但是如果是不明白其中原理的程序员可能还是会入坑的。下面总结几条使用建议:1.一定要实现Cloneable接口2.复写clone()方法,注意:默认是浅拷贝,这里需要将引用类型进行深拷贝处理3.特殊:String类虽然是引用类型,但是是final类,同时也有字符串常量池的存在,不必进行处理

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

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

相关文章

mysql实现内容加密_简单为mysql 实现透明加密方法

一般用户在数据库中保存数据,虽然数据库存储的是二进制,无法直接明文打开查看,但是如果是一个外行人,直接连接进入mysql中,还是可以直接查看数据的。所以对于一些核心数据,特别是企业重要数据资产&#xff…

Java之AQS(AbstractQueuedSynchronizer)

Java之AQS(AbstractQueuedSynchronizer) AQS 介绍 AQS 的全称为 AbstractQueuedSynchronizer ,翻译过来的意思就是抽象队列同步器。这个类在 java.util.concurrent.locks 包下面。 ● 是用来实现锁或者其他同步器组件的公共基础部分的抽象实…

SpringBoot 3.0最低版本要求的JDK 17,这几个新特性不能不知道

最近,有很多人在传说 SpringBoot要出3.0的版本了,并且宣布不再支持 Java 8,最低要求是 Java 17了。 其实,早在2021年9月份,关于 Spring Framework 6.0的消息出来的时候,Spring 官方就已经明确了不会向下兼…

jmeter mysql数据导出_Jmeter连接mysql

一、下载添加jar包image.png添加方法:1.拷贝到jmeter/lib目录下,此方法需重启jmeter2.直接在jmeter的测试计划中导入image.png二、连接mysql数据库添加配置元件-JDBC Connection Configurationimage.pngimage.png1.Variable Name for created pool&#…

判断一个坐标点是否在不规则多边形内部的算法

参考:https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html 在GIS(地理信息管理系统)中,判断一个坐标是否在多边形内部是个经常要遇到的问题。乍听起来还挺复杂。根据W. Randolph Franklin 提出的PNPoly算法,…

mysql++多版本安装_MySQL多版本多实例安装启动

多版本,大版本不同测试多实例,一个MySQL5.7.30一个MySQL8.0.20解压8.0tar -xvf mysql-8.0.20-linux-glibc2.12-x86_64.tartar -xJf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz改名移动/mysql8.0.20mv mysql-8.0.20-linux-glibc2.12-x86_64 /mysql8.0.2…

cheungssh mysql密码_CheungSSH安装及基本使用

CheungSSH比Ansible的使用更简单,尤其是配置方面!而Ansible有的功能, 我的这个程序一样有,和Ansible一样是python开发, 所以跟Ansible的模式一样, 但是CheungSSH 操作更简单!配置更轻量&#xf…

mybatis group by 分组查询:将返回结果封装为map

文章目录1. 最简单但性能最差的做法2. 使用group by分组查询&#xff0c;将查询结果封装成类3.group by分组查询&#xff0c;将结果封装为map。直接封装为map&#xff1f;List1. 最简单但性能最差的做法 在逻辑层分多次对数据库进行查询。伪代码如下。 List<String> na…

esl证明函 oracle_强弱分明 Astralis证明之战—ESL科隆B组浅析

HLTV排名前16名中的13支队伍(缺席的是G2和North)将齐聚这座坐落在莱茵河畔的城市进行厮杀&#xff0c;争夺比赛的最高荣誉。这项赛事也是继今年卡托维茨Major以来含金量最高&#xff0c;强队参赛最多的线下赛事。下面我们就来分析一下B组的出线形势。B组分组*本次比赛的赛制依旧…

关于new ArrayList()和Collections.emptyList()

很明显 new ArrayList()是创建一个Collection实例&#xff0c;它是Collection集合下面的一个实现类&#xff08;中间继承了AbstractList&#xff09;&#xff0c;它的实例有Collection的增加&#xff0c;删除&#xff0c;修改等方法&#xff0c; ArrayList平常用的很多&#x…

ArrayList()和Collections.emptyList()的区别emptyList()、emptySet()、emptyMap()的作用和好处以及要注意的地方

前言 Java中ArrayList或许是我们平时开发最常用的一个集合类了&#xff0c;其次是HashMap&#xff0c;基本上满足了业务开发的绝大多数场景。今天要说的就是Collections.emptyList()和new ArrayList()的区别以及注意事项。 先来一段代码 运行main方法&#xff0c;会有如下输出…

基于mysql搭建框架环境搭建_Maven+Spring+Spring MVC+MyBatis+MySQL,搭建SSM框架环境

项目建设完成之后的结构&#xff1a;数据库的表结构如下&#xff1a;环境建设&#xff1a;搭建Maven环境、Tomcat环境、需要MySql 数据库支持&#xff0c;使用的编程工具Eclipse (这些是前期准备)&#xff1b;开始创建工程&#xff1a;1.创建一个Maven工程&#xff1a;选择weba…

DataIntegrityViolationException: Error attempting to get column处理方案汇总

项目背景 项目整体采用的是springbootmybatis 方式。有一次做数据查询的时候。console突然报&#xff1a;DataIntegrityViolationException: Error attempting to get column ‘xx’…异常。起初没在意。以为是xml中的SQL写错了&#xff0c;排查了没问题。百度一下这个报错&…

Mybatis原理:结果集封装详解

​ 经过sql参数解析、sql动态组装和执行sql&#xff0c;相对而言&#xff0c;结果集的封装&#xff0c;是mybatis数据处理的最后一环。这里只对查询结果而言&#xff0c;因为更新语句一般都是返回影响的行数。抛开mybatis&#xff0c;如果让我们组装结果&#xff0c;我们该如何…

python内置函数面向对象_Pyhton——面向对象进阶二:类的内置函数补充、描述符...

Pyhton——面向对象进阶二&#xff1a;一、类的内置函数补充1、isinstance(obj,cls)——检查obj是否是该类的对象class Hoo:def __init__(self,name,tem):self.name nameself.tem temclass foo(Hoo):passf1foo(e,20)print(isinstance(f1,Hoo))首先 f1 肯定是 foo 的对象&…

vue项目打包后部署到服务器(超详细步骤)

耽误了几天, 终于开始写第二篇博客了, 这篇会讲怎么将vue项目打包部署到服务器, 其实和上一篇的uni-app步骤一样的, 就是最后多了一步修改nginx配置, 好 , 上操作 一 ,打包项目 vscode下载链接&#xff1a;https://pan.baidu.com/s/1ibHt7XB6EZy37BDb1CigWw 提取码&#xff1…

postman怎么不登陆使用_最新百度云不限速,免安装、免登陆、不限速,打开网站就能使用...

上次给大家安利了一波Pandownload手机版/电脑版。那篇文章中也说了&#xff0c;这类应用使用不当可能会遇到账号被限速的情况&#xff0c;而且手机版必须登录才能进行不限速下载。总之&#xff0c;凡是没登录账号的小伙伴&#xff0c;下载过程会非常曲折。那么是否有无需登录就…

vue项目配置打包测试环境/生产环境

vue项目配置打包测试环境/生产环境&#xff1a; 开发环境运行命令&#xff1a;npm run serve 生产环境打包命令&#xff1a;npm run pro 测试环境打包命令&#xff1a;npm run build 步骤&#xff1a; 1.项目中添加一个配置ip的js文件&#xff0c;比如如下的ip-config.js&…

SpringMVC访问WEB-INF下的jsp解决方案Spring Boot集成使用jsp

SpringMVC访问WEB-INF下的jsp解决方案 一. 问题 ​将项目中用到的jsp等文件放在WEB-INF目录下。实际开发过程中&#xff0c;需要在框架页面通过iframe嵌入对应的具体页面&#xff0c;此处如果直接调用对应页面所在的url地址&#xff0c;则会提示404错误。 ​ WEB-INF目录下的…

SpringBoot | 详解SpringBoot配置文件及其原理

文章目录一、配置文件二、YAML语法1、基本语法2、值的写法(1)、字面量&#xff1a;普通的值&#xff08;数字&#xff0c;字符串&#xff0c;布尔&#xff09;(2)、对象、Map&#xff08;属性和值&#xff09;(3)、数组&#xff08;List、Set&#xff09;三、配置文件值注入1、…