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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

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

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

python日期转化成周数_[转]浅析使用python计算两个日期间隔天数﹑周数和指定若干天后对应的日期等...

>>> import datetime>>> help(datetime)http://docs.python.org/library/datetime.html查看2009年5月31日和2009年2月1日间隔多少天>>> d1datetime.date(2009,05,31)>>> d2datetime.date(2009,02,01)>>> d1-d2datetime.timedelta…

python笔记小白入门_Python 笔记:全网最详细最小白的Class类和实例详解

面向对象最重要的概念就是类(class)和实例(instance)&#xff0c;类是抽象&#xff0c;而实例(Instance)则是一个个具体的对象面向对象三大特点&#xff1a;封装、继承和多态class Animal(object):def __init__(self, name):self.name name # 初始化类变量def Dog(self): # 创…

java 字符串转dom对象_xml类型的字符串转换为Dom对象

我写这篇博客的目的是因为我在这一点转换方面耽搁了快2天时间&#xff0c;真是惭愧呀&#xff0c;dom4j.jar包有自带方法DocumentHelper.parseText(String text)用于将字符串类型的xml转换为Dom对象&#xff0c;从而进行下面的解析&#xff0c;还有一个关键是&#xff1a;产生字…

java nlpir_中科院NLPIR中文分词java版

摘要&#xff1a;为解决中文搜索的问题&#xff0c;最开始使用 版 SCWS &#xff0c;但是处理人名和地名时&#xff0c;会出现截断人名地名出现错误。开始使用 NLPIR 分词&#xff0c;在分词准确性上效果要比 SCWS 好。本文介绍如何在 系统下 JAVA &#xff0c;生成可以执行的 …

java怎编写么解析一个类型_DAY3:你必须知道的java虚拟机之类篇——类文件的结构...

马上过年啦&#xff0c;不知道大家今年有没有投资基金股票呢&#xff1f;是赚的盆满钵满还是拍断大腿&#xff0c;可以评论区一起交流交流&#xff0c;秀一秀哈哈&#xff0c;反正我是没来得及上车。暴富西不可能暴富的啦&#xff0c;打工人嘛几能写写文章啦&#xff5e;记得点…

java自学笔记_JAVA自学笔记(4)

发现JAVA的有趣Day1 继承不是"继承"1.0 继承的格式public classFU {public voidmethod(){System.out.println("Good night!");}}public class ZI extendsFU {}public classPractice {public static voidmain(String[] args) {ZI zinewZI();zi.method();}}打…

java分隔符算法_《Java数据结构和算法》栈 分隔符分配

分隔符包括“&#xff5b;“、"["、”(”、“] “、“)“、“&#xff5d;”&#xff0c;每个左分隔符需要右分隔符匹配。同时&#xff0c;在字符串中后出现左分隔符应该比早出现的先匹配。程序从字符串中不断读取字符&#xff0c;每次读取一个字符。若发现是左分隔符…

Java集合迭代器原理图解_Java Iterator接口遍历单列集合迭代器原理详解

这篇文章主要介绍了Java Iterator接口遍历单列集合迭代器原理详解,文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下Iterator接口概述在程序开发中&#xff0c;经常需要遍历集合中的所有元素。针对这种需求&#x…

php商城的购物车功能,php实现购物车功能(以大苹果购物网为例)

首先是几个简单的登录页面登录用户名&#xff1a;密 码&#xff1a;登录页面写好之后&#xff0c;需要进入处理页面&#xff0c;从数据库中调出用户名和密码&#xff1a;session_start(); //开启session 必须要写到第一行header("Content-type:text/html;charsetutf-8&quo…

php的功能和特点,php的特点有哪些

PHP是一种服务器端、跨平台、html嵌入式的脚本语言执行速度快&#xff1a;PHP是一种强大的CGI脚本语言&#xff0c;语法混合了C、Java、Perl和PHP式的新语法&#xff0c;执行网页比CGI、Perl和ASP更快&#xff0c;这是它的第一个突出的特点。 (推荐学习&#xff1a;PHP视频教程…

php小程序码生成并保存,小程序中如何生成小程序码

导语&#xff1a;小程序是一种不需要下载安装即可使用的应用&#xff0c;它实现了应用“触手可及”的梦想&#xff0c;用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念&#xff0c;用户不用关心是否安装太多应用的问题。应用将无处不在&#xff0c;随时可用&…

php写不了php,php写入内存不足怎么办

php写入内存不足的解决办法&#xff1a;1、修改【php.ini】&#xff1b;2、在程序里面添加相关语句&#xff0c;代码为【ini_set(memory_limit, 12M)】&#xff1b;3、在根目录建立【.htaccess】文件。本教程操作环境&#xff1a;windows7系统、PHP5.6版&#xff0c;DELL G3电脑…

java 终态类,javaoo,继承,抽象类,终态类,访问修饰符!

java的继承&#xff01;Java的继承使用extends关键字&#xff01;为什么要使用继承呢&#xff1f;我们先来举例说明一下&#xff01;比如说&#xff01;烟是类&#xff01;而叶子烟&#xff0c;和纸烟&#xff0c;烟这个类包含了&#xff0c;叶子烟和纸烟这两个类&#xff0c;如…

php cdr,win10彻底禁止cdr联网

1、打开Win10电脑&#xff0c;然后按winPauseBreak&#xff0c;来到“系统”属性窗口&#xff0c;点击控制面板&#xff0c;如图所示&#xff1a;2、打开来到控制面板页面&#xff0c;鼠标单击“系统和安全”&#xff0c;如图&#xff1a;3、打开在“系统和安全”对话框中&…

微信 语音转文字 java,在微信——怎么将语音转化为文字,你需要学习了

有时候和好友在聊天&#xff0c;这时好友在微信上发来语音信息&#xff0c;可是你这个时候不方便听语音&#xff0c;那怎么办呢&#xff1f;这个是我们就可以运用微信的语音转文字的功能&#xff0c;那么如何使用这个功能呢&#xff1f;跟着小编看看吧&#xff01;操作方法01小…

php开发添加表情功能,WordPress网站评论区如何实现添加表情包功能?

做网站过程中&#xff0c;可以给自己的网站添加评论框&#xff0c;供用户评论。默认情况下&#xff0c;Wordpress网站评论框是没有添加表情功能的&#xff0c;那么WordPress网站评论区如何实现添加表情包功能&#xff1f;今天我们介绍一下如何给自己的Wordpress网站评论框添加表…