java list拷贝_深入了解浅拷贝与深拷贝

cfc3ac6b6feff9db4bb52c12272ade09.png

在学习深拷贝和浅拷贝之前,咱们先来一个例子:

import java.util.ArrayList;public class MyBaby implements Cloneable {/*** 私有变量*/private ArrayList<String> list = new ArrayList<>();@Overrideprotected Object clone() throws CloneNotSupportedException {MyBaby myBaby = null;try {myBaby = (MyBaby) super.clone();} catch (CloneNotSupportedException ex) {ex.printStackTrace();}return myBaby;}/*** 给List设置** @param value 值*/public void setValue(String value) {this.list.add(value);}/*** 获取list** @return list*/public ArrayList<String> getValue() {return this.list;}
}

在MyBaby类中有一个私有变量list,类似为List,然后咱们使用setValue对其进行设值,使用getValue进行取值。接下来咱们来看看他是如何拷贝的。

public class TestMyBaby {public static void main(String[] args) {MyBaby baby = new MyBaby();baby.setValue("Java后端技术栈");try {MyBaby myBabyClone = (MyBaby) baby.clone();myBabyClone.setValue("咖啡");System.out.println(baby.getValue());} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

猜想运行结果会是神马?

[Java后端技术栈, 咖啡]

怎么会这样呢?怎么会有“咖啡”呢?

是因为Java给我们做了一个偷懒性的拷贝动作,Object类原本就提供一个方法clone用来拷贝对象,因为其对象内部的数组、引用对象等都不拷贝,还是指向了原生对象的内部元素地址,这种拷贝就叫做浅拷贝

浅拷贝

上面这个拷贝也太浅了吧,两个对象引用都boby、myBaby共享一个私有变量list,都可以对list进行改变,是一种非常不安全的方式。

14464e3d1c75d51b4bfdeac1f54c0bce.png

再看一个例子;

public class Person implements Cloneable {private int age;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {Person person=null;try{person=(Person)super.clone();}catch (CloneNotSupportedException ex){ex.printStackTrace();}return person;}
}

来写一个测试类,对其clone方法进行测试:

public class TestPerson {public static void main(String[] args) throws CloneNotSupportedException {Person person = new Person();person.setAge(22);person.setName("Java后端技术栈");//克隆一个对象Person clone = (Person) person.clone();//对person的age重新赋值为25person.setAge(25);//对person的age重新赋值为25person.setName("咖啡");System.out.print(clone.getAge()+","+clone.getName());}
}

运行后将输出什么呢?先猜想一下。

具体运行结果如下:

22,Java后端技术栈

是不是觉得很神奇呢?为什么没有变化呢?

原始数据类型会被拷贝,如果从原始数据类型考虑,因为age是int类型,int是原始数据类型,所以上述场景没变,那也就无话可说,但是String并不是原始数据类型,那又是为什么呢?因为String是一个特殊类型,因为这种场景下Java希望String也看成原始类型。所以String并没有clone方法。

String aa="aa";
aa.clone();

String定义

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {//...省略其他
}

这段代码编译通不过,提示无法访问,为什么呢?请看Object源码中对clone方法的定义

  protected native Object clone() throws CloneNotSupportedException;

String处理机制比较特殊,通过字符串池在需要的时候再内存中创建新的字符串,以后大家就在使用(clone)的时候就直接把String当做原始数据类型就行了。

深拷贝

浅拷贝是有风险的,那么如何才能深拷贝呢?我们对前面的Mybaby程序进行修改一下就成了深拷贝了;

a85c2027a861dbd9a675707c79b53a25.png
import java.util.ArrayList;/*** @author tianweichang* @date 2019/7/13*/
public class MyBaby implements Cloneable {/*** 私有变量*/private ArrayList<String> list = new ArrayList<>();@SuppressWarnings("unchecked")@Overrideprotected Object clone() throws CloneNotSupportedException {MyBaby myBaby = null;try {myBaby = (MyBaby) super.clone();//增加了一个list.clone();this.list = (ArrayList<String>) this.list.clone();} catch (CloneNotSupportedException ex) {ex.printStackTrace();}return myBaby;}/*** 给List设置** @param value 值*/public void setValue(String value) {this.list.add(value);}/*** 获取list** @return list*/public ArrayList<String> getValue() {return this.list;}
}

再次运行TestMyBaby,结果:

[Java后端技术栈]

改短代码就实现了完全的拷贝,两个对象引用指向的就不再是同一个地址了。相互之间没有什么关系了,你修改你的,我修改我的,完全不会有什么安全问题。这就是深拷贝

深拷贝还有一种实现方式:通过写自己的二进制流来操作对象,然后实现对象的深拷贝。

建议

深拷贝和浅拷贝不要混合使用,特别是在涉及到类的继承时候,父类中有多个引用的情况下就会非常复杂,建议方案是深拷贝和浅拷贝分开实现。

clone与final两个冤家

对象的clone与对象内的final关键字是有冲突,前者是要重新赋值,后者是赋值了就不能变了。

咱们继续帮上忙的代码进行改造:

public class MyBaby implements Cloneable {/*** 私有变量*/private final ArrayList<String> list = new ArrayList<>();@SuppressWarnings("unchecked")@Overrideprotected Object clone() throws CloneNotSupportedException {MyBaby myBaby = null;try {myBaby = (MyBaby) super.clone();//下面的this.list编译通不过,提示不能给final修饰的变量重新赋值this.list = (ArrayList<String>) this.list.clone();} catch (CloneNotSupportedException ex) {ex.printStackTrace();}return myBaby;}/*** 给List设置** @param value 值*/public void setValue(String value) {this.list.add(value);}/*** 获取list** @return list*/public ArrayList<String> getValue() {return this.list;}
}

所以请注意,要使用clone方法的时候,类的成员变量上不要加final修饰。

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

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

相关文章

吗 极域软件可以装win10_关于win10企业版在极域电子教室软件 v4.0 2015 豪华版的全屏控制下如何取得自由...

注.可能因为系统和软件的缘故无法实现背景由于在听课过程过于自闭&#xff0c;于是想自己去网上搜点东西看下于是 经过了一番乱搞 逐渐摸索出了现方法。方案1:大力出奇迹由于电脑在刚刚进入的状态的时候有段时间是断网的并且该鬼畜的学生端可以通过任务资源管理器直接退所以可以…

python怎么启动mne_mne-python学习之一 入门介绍

mne-python脑电图和肌电图是一个开源软件分析、处理和显示。遵循bsd许可协议,由哈佛大学和共同开发的社区。主要功能包括:预处理和脑电图\/梅格信号的去噪,源估计、时频分析、统计测试,功能连接,机器学习,可视化的传感器、来源等外资支持最常见的原始数据格式。默认的(和附带的…

dcdc升压计算器excel_DC/DC升压转换器MAX8815A

DC&#xff0f;DC升压转换器MAX8815A佚名【摘要】MAX8815A具有97&#xff05;的最高效率、3OuA低静态电流以及低噪声强制PWM工作模式。该boost转换器专为2节NiMH&#xff0f;NiCdAA电池或单节Li&#xff0b;电池输入设计&#xff0c;可从1&#xff0e;2&#xff5e;5&#xff0…

python类怎么实例化rnn层_Python backend.rnn方法代码示例

本文整理汇总了Python中keras.backend.rnn方法的典型用法代码示例。如果您正苦于以下问题&#xff1a;Python backend.rnn方法的具体用法&#xff1f;Python backend.rnn怎么用&#xff1f;Python backend.rnn使用的例子&#xff1f;那么恭喜您, 这里精选的方法代码示例或许可以…

vscode删除文件夹,VSCode:删除文件中的所有注释

Is there an easy way to delete all comments from an open file in VSCode? Preferably both line and block comments.Most interested in Java, but also Python and R.解决方案Easy way:Open extensions (ctrl-shift-x)type in remove comments in the search box.Instal…

放大镜_屏幕放大镜怎么样使用方法

首先&#xff0c;打开控制面板&#xff0c;然后找到并单击“显示”&#xff0c;然后启动放大镜。放大镜的放大倍率基于原始屏幕&#xff0c;而不是矢量放大倍率。有关放大镜的详细操作&#xff0c;请单击帮助按钮&#xff0c;其中有特定说明。捷径一&#xff1a;win 可以快速调…

python清空语句_怎么清除python编译器的语句

清除python编辑器的方法&#xff1a;1、下载清屏函数clearwindow.py&#xff0c;然后复制clearwindow.py文件&#xff0c;并放在Python安装目录PythonXLibidlelib下面2、在Python XLibidlelib目录下找到config-extensions.def(IDLE扩展的配置文件)&#xff0c;用记事本打开&…

mysql字段是否存在_Mysql判断表字段或索引是否存在

判断字段是否存在&#xff1a;DROP PROCEDURE IF EXISTS schema_change;DELIMITER //CREATE PROCEDURE schema_change() BEGINDECLARE CurrentDatabase VARCHAR();SELECT DATABASE() INTO CurrentDatabase;IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE tabl…

mysql取消主键_mysql如何删除主键?

当一个表中设置了主键之后&#xff0c;如果想要删除主键了要怎么做&#xff1f;下面本篇文章就给大家介绍MySQL删除主键的方法&#xff0c;希望对你们有所帮助。首先我们来看看删除主键的语法&#xff1a;ALTER TABLE TABLE_NAME DROP PRIMARY KEY;在MySQL中删除主键要考虑两种…

mysql 备份 windows_windows mysql 自动备份的几种方法

基于之前的文章方法&#xff0c;加入批处理命令即可实现自动备份。只是由于批处理命令中对于备份文件的名字按照时间命名比较特别&#xff0c;所以特别整理一文。1、复制date文件夹备份假想环境&#xff1a;MySQL 安装位置&#xff1a;C:\MySQL论坛数据库名称为&#xff1a;b…

mysql长事务慢查询解决方案_MySQL : 如何监控和处理慢查询与长事务 ?

什么是慢查询、长事务 &#xff1f;慢查询 是指一条 SQL 的执行时间太长。比如在一个有100w条数据的表中&#xff0c;查询一条数据时未命中索引&#xff0c;从而通过全表扫描查询数据&#xff0c;这个查询会耗时很长。这就是一个 Long SQL 。类似&#xff0c;更新数据、删除数据…

mysql身份验证失败_SMTP身份验证失败PAM-MySQL无法进行身份验证

我正在使用Postfix构建邮件服务器,并设置身份验证以使用Postfixadmin检查数据库设置.我可以通过Courier IMAP进行身份验证,因为它可以正确地验证哈希密码,但我怀疑我的SASL PAM-MySQL SMTP身份验证机制不能.我在/var/log/mail.log中收到这些错误&#xff1a;pam_unix(smtp:auth…

二级数据库access和mysql_二级数据库access和mysql

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

mysql 从库可以写入吗_mysql主从库配置读写分离以及备份

1&#xff0c;什么是读写分离&#xff1f;其实就是将数据库分为了主从库&#xff0c;一个主库用于写数据&#xff0c;多个从库完成读数据的操作&#xff0c;主从库之间通过某种机制进行数据的同步&#xff0c;是一种常见的数据库架构。一个组从同步集群&#xff0c;通常被称为是…

用程序同步mysql数据库表_初次用Java写了个数据库表同步工具

介绍java 程序编写&#xff0c;真正跨平台。传入一定的参数&#xff0c;即可在相同或不同的数据库间进行表的同步&#xff0c;包括表结构的同步及数据的同步。作业由调度工具进行调度&#xff0c;比如 moia&#xff0c;本项目旨在提供一种数据库间表同步的通用工具。目前项目 d…

公认音质好的耳机品牌_什么品牌蓝牙耳机音质比较好?2020五款HIFI音质蓝牙耳机推荐...

对于蓝牙耳机&#xff0c;绝大多数人的需求都是听音乐&#xff0c;同时也作为一个穿戴的修饰品。基于这些需求&#xff0c;在我们选择蓝牙耳机的时候&#xff0c;就会选择一些外观比较好看的时尚音乐蓝牙耳机&#xff0c;既有时尚的外观&#xff0c;又有较好的音质。那么现在有…

mysql创建表时在extra输入数据_MySQL创建数据表(CREATE TABLE语句)

在创建数据库之后&#xff0c;接下来就要在数据库中创建数据表。所谓创建数据表&#xff0c;指的是在已经创建的数据库中建立新表。创建数据表的过程是规定数据列的属性的过程&#xff0c;同时也是实施数据完整性(包括实体完整性、引用完整性和域完整性)约束的过程。接下来我们…

mysql not in报错_mysql从5.7升级到8.0查询报错Expression #2 of SELECT list is not in GROUP BY...

报错信息&#xff1a;Expression #2 of SELECT list is not in GROUP BY clause and containsnonaggregated column ‘sss.month_id’ which is not functionallydependent on columns in GROUP BY clause; this is incompatible withsql_modeonly_full_group_by问题出现的原因…

mysql取消操作系统_Linux下的MySQL简单操作(服务启动与关闭、启动与关闭、查看版本)...

小弟今天记录一下在Linux系统下面的MySQL的简单使用&#xff0c;如下&#xff1a;服务启动与关闭 启动与关闭 查看版本环境Linux版本&#xff1a;centeros 6.6(下面演示)&#xff0c;Ubuntu 12.04(参见文章末尾红色标注字体)MySQL版本&#xff1a;5.1.73查看MySQL服务的启动状态…

python文件下载速度 装饰器_python使用装饰器对文件进行读写操作'及遍历文件目录...

‘‘‘使用装饰器对文件进行读写操作‘‘‘#def check_permission(func):#‘‘‘演示嵌套函数定义及使用‘‘‘#def wrapper(*args,**kwargs):#‘‘‘*args:接收任意多个实参并存入元组中&#xff1b;**kwargs:接收关键字参数显示赋值并存入字典中‘‘‘#if kwargs.get(‘usern…