java对象的克隆以及深拷贝与浅拷贝
一、为什么要使用克隆
在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在 Java语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。
使用new和赋值语句或者set注入都是可以的,但是,这会花费大量开销去做,效率低,并且还会产生冗余代码。Object的clone()方法是在java平台层实现的native方法,具有开销小,速度快的特点。
二、克隆的实现
- 需要克隆的类实现Cloneable接口
- 需要克隆的类复写clone方法,并在方法中调用父类的clone方法
package com.javaBase.clone; /**
* 〈一句话功能简述〉;
* 〈对象克隆〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class Workers implements Cloneable { /**
* 复写父类的clone方法
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} public static void main(String[] args) throws Exception {
Workers w = new Workers();
Workers w2 = (Workers)w.clone();
System.out.println(w == w2);
}
}
运行结果:false
显然w2是w的克隆,并且是一个新的对象。这便是简单的克隆实现。
三、深克隆与浅克隆
浅拷贝:仅仅克隆基本类型变量,而不克隆引用类型的变量
深克隆:既克隆基本类型变量,也克隆引用类型变量
代码示例:
package com.javaBase.clone; /**
* 〈一句话功能简述〉;
* 〈功能详细描述〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class Boss implements Cloneable { private String name;
private char sex; public Boss(String name, char sex) {
this.name = name;
this.sex = sex;
} public char getSex() {
return sex;
} public void setSex(char sex) {
this.sex = sex;
} public String getName() { return name;
} public void setName(String name) {
this.name = name;
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.javaBase.clone; /**
* 〈一句话功能简述〉;
* 〈浅拷贝〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class Workers implements Cloneable { private String name;
private char sex;
private Boss boss; public Workers(String name, char sex, Boss boss) {
this.name = name;
this.sex = sex;
this.boss = boss;
} /**
* 复写父类的clone方法
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} public static void main(String[] args) throws Exception {
Boss boss = new Boss("马云",'男');
Workers w = new Workers("张三",'女',boss);
Workers w2 = (Workers) w.clone();
System.out.println(w.name == w2.name); //true
System.out.println(w.sex == w2.sex); //true
System.out.println(w.boss == w2.boss); //true w.name = "李四";
System.out.println(w.name == w2.name); //false w.boss.setName("马化腾");
System.out.println(w.boss.getName() == w2.boss.getName()); //true 修改w对象的boss的属性值,w2对象中的值也跟随发生了变化
}
}
以上是一个浅拷贝的例子,Boss是一个引用类型,当w对象克隆体w2中的boss引用和w2指向的是同一片内存区域,因此,修改其中一个的boss属性值。另一个也会随着发生变化。因此当对象属性中存在引用类型时,需要进行深拷贝。下面是深拷贝代码:
package com.javaBase.clone; /**
* 〈一句话功能简述〉;
* 〈深拷贝〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class Workers implements Cloneable { private String name;
private char sex;
private Boss boss; public Workers(String name, char sex, Boss boss) {
this.name = name;
this.sex = sex;
this.boss = boss;
} /**
* 复写父类的clone方法
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
Workers w = (Workers)super.clone();
//拷贝一份新的引用类型
w.boss = (Boss)this.boss.clone();
return w;
} public static void main(String[] args) throws Exception {
Boss boss = new Boss("马云",'男');
Workers w = new Workers("张三",'女',boss);
Workers w2 = (Workers) w.clone();
System.out.println(w.name == w2.name); //true
System.out.println(w.sex == w2.sex); //true
System.out.println(w.boss == w2.boss); //false w.name = "李四";
System.out.println(w.name == w2.name); //false w.boss.setName("马化腾");
System.out.println(w.boss.getName() == w2.boss.getName()); //false 修改w对象的boss的属性值,w2对象中的值没有跟随变化
}
}
可见深拷贝情况下,w2与w拥有两个不同的对象boss。
四、String类型的特殊性
我们知道对于引用类型需要进行深度拷贝,但String类型是个例外,String类型的变量clone后的表现好象也实现了深度clone,但其实只是一个假象。因为执行 cloned.name = "new";语句时,它作用相当于生成了一个新的string类型,然后又赋回给cloned.name。这是因为string被sun公司的工程师写成了一个不可更改的类(immutable class),在所有string类中的函数都不能更改自身的值。
五、总结
- 浅克隆:只复制基本类型的数据,引用类型的数据只复制了引用的地址,引用的对象并没有复制,在新的对象中修改引用类型的数据会影响原对象中的引用。直接使用
clone方法,再嵌套的还是浅克隆,因为有些引用类型不能直接克隆。 - 深克隆:是在引用类型的类中也实现了
clone,是clone的嵌套,并且在clone方法中又对没有clone方法的引用类型又做差异化复制,克隆后的对象与原对象之间完全不会影响,但是内容完全相同。 - 使用序列化也能完成深复制的功能:对象序列化后写入流中,此时也就不存在引用什么的概念了,再从流中读取,生成新的对象,新对象和原对象之间也是完全互不影响的。
参考链接:什么是对象克隆(拷贝/复制)?浅克隆与深克隆有什么区别?
java对象的克隆以及深拷贝与浅拷贝的更多相关文章
- JAVA中对象的克隆及深拷贝和浅拷贝
使用场景: 在日常的编程过程 中,经常会遇到,有一个对象OA,在某一时间点OA中已经包含了一些有效值 ,此时可能会需一个和OA完全相对的新对象OB,并且要在后面的操作中对OB的任何改动都不会影响到OA ...
- 【JAVA零基础入门系列】Day14 Java对象的克隆
今天要介绍一个概念,对象的克隆.本篇有一定难度,请先做好心理准备.看不懂的话可以多看两遍,还是不懂的话,可以在下方留言,我会看情况进行修改和补充. 克隆,自然就是将对象重新复制一份,那为什么要用克隆呢 ...
- java对象克隆以及深拷贝和浅拷贝
1.什么是"克隆"? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不 ...
- java克隆之深拷贝与浅拷贝
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问 ...
- Java对象的克隆
今天要介绍一个概念,对象的克隆.本篇有一定难度,请先做好心理准备.看不懂的话可以多看两遍,还是不懂的话,可以在下方留言,我会看情况进行修改和补充. 克隆,自然就是将对象重新复制一份,那为什么要用克隆呢 ...
- 深入理解Java中的Clone与深拷贝和浅拷贝
1.Java对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象. ...
- java对象 深度克隆(不实现Cloneable接口)和浅度克隆
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128 为什么需要克隆: 在实际编程过程中,我们常常要遇到这种情况:有一个对象 ...
- javascript对象和数组之 深拷贝和浅拷贝
管是在面试中还是我们的项目中经常会用到数组或者对象的深拷贝,下面我就自己总结的分享给大家. 首先要知道什么是深拷贝?什么是浅拷贝? 深拷贝:源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外 ...
- Java对象的克隆和深浅问题
Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...
随机推荐
- RFC3918组播转发时延测试——网络测试仪实操
一.简介 1.RFC3918简介 历史 · 在1999年3月成为正式标准 功能 · 评测网络互连设备或网络系统的性能 · 网络设备: 交换机,路由器- 内容 · 定义了一整套测试方法,为不同厂家的设备 ...
- RFC3918组转发矩阵测试——网络测试仪实操
一.简介 1.RFC3918简介 历史 · 在1999年3月成为正式标准 功能 · 评测网络互连设备或网络系统的性能 · 网络设备: 交换机,路由器- 内容 · 定义了一整套测试方法,为不同厂家的设备 ...
- 报表工具和BI商业智能的区别,你真的弄清楚了吗?
许多人在投身大数据行业的时候,肯定会听到的两个词就是"报表工具"和"BI商业智能".但是大部分人并不太清楚这两者之间的概念和区别,认为报表就是BI,BI就是报表 ...
- 二叉树的N中遍历方式和拓展应用
(一)创建二叉树,如下图所示,一个标准的二叉树是所有位于根节点的左侧的子节点都是比根节点小的,右侧则都是大于根节点的. public class BinaryNode { public int val ...
- GAN实战笔记——第六章渐进式增长生成对抗网络(PGGAN)
渐进式增长生成对抗网络(PGGAN) 使用 TensorFlow和 TensorFlow Hub( TFHUB)构建渐进式增长生成对抗网络( Progressive GAN, PGGAN或 PROGA ...
- JZ-033-丑数
丑数 题目描述 把只包含质因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含质因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. ...
- LeetCode-025-K 个一组翻转链表
K 个一组翻转链表 题目描述:给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保 ...
- 使用Three.js实现神奇的3D文字悬浮效果
声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 在 Three.js Journey 课程示例中,提供了一个使用 Thre ...
- [csi]浅聊ceph-csi组件
描述 ceph-csi扩展各种存储类型的卷的管理能力,实现第三方存储ceph的各种操作能力与k8s存储系统的结合.调用第三方存储ceph的接口或命令,从而提供ceph数据卷的创建/删除.挂载/解除 ...
- Centos8 Yum 安装Nginx指定版本
查看系统和EPEL的nginx版本 dnf info nginx 通过官方 yum 源安装nginx vi /etc/yum.repos.d/nginx.repo 列出所有版本 ...