Java的clone():深复制与浅复制
Java中要想自定义类的对象可以被复制,自定义类就必须实现Cloneable中的clone()方法,如下:
public class Student implements Cloneable {
private String name;
private int age;
private Professor professor;
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 Professor getProfessor() {
return professor;
}
public void setProfessor(Professor professor) {
this.professor = professor;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", professor="
+ professor + "]";
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
其中,Professor类同样为自定义类:
public class Professor {
private String name;
private int age;
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;
}
@Override
public String toString() {
return "Professor [name=" + name + ", age=" + age + "]";
}
}
然而,当自定义类的字段的类型不是基本数据类型时,上面实现了clone()方法会导致问题,不信看下面的代码:
【程序实例1】
public class ShadowCopy {
public static void main(String[] args) {
Professor p1 = new Professor();
p1.setName("Professor Zhang");
p1.setAge(30);
Student s1 = new Student();
s1.setName("xiao ming");
s1.setAge(18);
s1.setProfessor(p1);
System.out.println(s1);
try {
Student s2 = (Student) s1.clone();
Professor p2 = s2.getProfessor();
p2.setName("Professor Li");
p2.setAge(45);
s2.setProfessor(p2);
System.out.println("复制后的:s1 = " + s1);
System.out.println("复制后的:s2 = " + s2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
【运行结果1】
Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]
复制后的:s2 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]
【结果分析】
学生s1的导师为30岁的Professor Zhang,恰好学生s2与学生s1同名同岁,但是s2的导师为45岁的Professor Li,于是我们顺理成章地复制复制s1并复制给s2,再修改下s2的导师的信息。可是,问题出现了,当我们修改了s2的导师后,s2的信息是对了,但是s1的导师信息也跟着修改了,这可不是我们期望的。
【问题分析】
程序实例1中的问题出在哪儿呢?我们已经对Student类实现了clone()方法,怎么还是出问题了呢?我们在看下面的代码:
【程序实例2】
public class ShadowCopy {
public static void main(String[] args) {
Professor p1 = new Professor();
p1.setName("Professor Zhang");
p1.setAge(30);
Student s1 = new Student();
s1.setName("xiao ming");
s1.setAge(18);
s1.setProfessor(p1);
System.out.println(s1);
try {
Student s2 = (Student) s1.clone();
s2.setName("xiao hong");
s2.setAge(17);
Professor p2 = s2.getProfessor();
p2.setName("Professor Li");
p2.setAge(45);
s2.setProfessor(p2);
System.out.println("复制后的:s1 = " + s1);
System.out.println("复制后的:s2 = " + s2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
【运行结果】
Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]
复制后的:s2 = Student [name=xiao hong, age=17, professor=Professor [name=Professor Li, age=45]]
【结果分析】
这次,我们在clone后,又修改了s2的name和age,从结果可以看出,s1的name和age并没有因为s2的修改而改变。
结合程序实例1和程序实例2,我们发现Student的字段如果不是一个引用时,修改clone()得到对象的该字段(name, age)时并不会影响原来的对象,但是当字段为一个引用时,修改clone()得到对象的该字段(professor)时并会影响原来的对象。上面实现的clone()方法为浅复制(shadow copy)。
如果想要clone()得到的新对象的修改不会影响被复制的对象的字段时,我们就需要实现深复制(deep copy),代码修改如下:
public class Professor implements Cloneable {
private String name;
private int age;
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;
}
@Override
public String toString() {
return "Professor [name=" + name + ", age=" + age + "]";
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
public class Student implements Cloneable {
private String name;
private int age;
private Professor professor;
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 Professor getProfessor() {
return professor;
}
public void setProfessor(Professor professor) {
this.professor = professor;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", professor="
+ professor + "]";
}
public Object clone() throws CloneNotSupportedException{
Student newStudent = (Student) super.clone();
newStudent.professor = (Professor) professor.clone();
return newStudent;
}
}
再次运行【程序实例2】得到的结果为:
Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
复制后的:s2 = Student [name=xiao hong, age=17, professor=Professor [name=Professor Li, age=45]]
可以看到:修改clone()得到的s2的任何字段都不会影响s1的字段,这也就是深复制的作用。
参考资料:
1、http://pengcqu.iteye.com/blog/493120
2、http://www.cnblogs.com/shuaiwhu/archive/2010/12/14/2065088.html
Java的clone():深复制与浅复制的更多相关文章
- Java中的clone()----深复制,浅复制
这篇文章主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他 ...
- Java中对象的深复制和浅复制详解
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
- Java中的深复制与浅复制
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不 复制它所引用的对象. ...
- clone()方法、深复制和浅复制
clone方法 Java中没有明确提供指针的概念和用法,而实质上没个new语句返回的都是一个指针的引用,只不过在大部分情况下开发人员不需要关心如何去操作这个指针而已. 在实际编程中,经常会遇到从某个已 ...
- C#深复制与浅复制
C#深复制与浅复制 C#中对于数据的复制机制虽然简单但是容易让人误解.C#数据类型大体分为值类型(value type)与引用类型(reference type).对于值类型数据,复制的时候直接将数据 ...
- js中的深复制与浅复制
前言 所谓深复制与浅复制(深拷贝与浅拷贝),乍一听感觉听高大上,像是一个非常难理解的概念,其实我们平常项目开发都是在用的,只是你可能不知道该怎么叫它的名字而已,就像你听熟了一首歌,就是不知道这首歌叫什 ...
- .Net深复制、浅复制
在.Net,大家都知道引用类型的深复制.浅复制吧. ,一般int等值类型是值类型(复制时是直接传值),一般的类(List<T>,Class)是引用类型(复制时传地址),默认是浅复制.若ob ...
- C++学习基础七——深复制与浅复制
一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深 ...
- php对象当参数传递 && php深复制和浅复制
把对象当参数传递给方法,在方法里改过对象后,影响到外面的对象 因为对象是引用传递过去的 class Book { public $name; public function __construct( ...
- iOS 集合的深复制与浅复制
概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制 ...
随机推荐
- Java虚拟机学习笔记(一)
Java虚拟机运行时数据区域 Java虚拟机将其所管理的内存划分为若干个不同的数据区域.这些区域都有着各自的用途,以及创建和销毁时间.其中有一些会随着虚拟机启动而启动,随着虚拟机退出而销毁:有些则是与 ...
- 零基础学Python--------第4章 序列的应用
第4章 序列的应用 4.1序列 序列是一块用于存放多个值的连续内存空间,并且按上一定顺序排列,每一个值(称为元素)都分配一个数字,称为索引或位置.通过该索引可以取出相应的值.例如,我们可以把一家酒店看 ...
- 2019元月新SAP项目落地记
2019元月新SAP项目落地记 ~ 追求绝对安全感,要求无缝衔接 ~ 元旦刚过,我就开始了新SAP项目的寻找之旅. 笔者追求绝对的安全感,以及新旧项目之间的无缝衔接.即不能让自己长时间的闲着无项目做, ...
- 外媒评李开复的《AI·未来》:四大浪潮正在席卷全球
外媒评李开复的<AI·未来>:四大浪潮正在席卷全球 https://mp.weixin.qq.com/s/oElub0QOYjOROhqN3ULUkg [网易智能讯 9月17日消息]李开复 ...
- Fragment已经被added了导致的异常。
java.lang.IllegalStateException: Fragment already added: ******Effect 出现的原因是commit方法提交是异步的,所以容易出现,判 ...
- asp.net core webapi/website+Azure DevOps+GitHub+Docker
asp.net core webapi/website+Azure DevOps+GitHub+Docker 新春开篇作,主要写一下关于asp.net core web/api 2.2 项目借助dev ...
- dede后台删除文章后台还有分页显示解决方法
打开dede目录中content_list.php 大概在100行左右 $sql = "SELECT COUNT(*) AS dd FROM `#@__arctiny` $tinyQuery ...
- Word Count作业
Word Count作业 一.个人Gitee地址:https://gitee.com/Changyu-Guo 二.项目简介 该项目主要是模拟Linux上面的wc命令,基本要求如下: 命令格式: wc. ...
- 2016 西普杯丶天津CTF预选赛(3/6)
哆啦A梦(图片隐写) 格式:SimCTF{ } 解:放到kail中binwalk一下(Binwalk是一个固件的分析工具,旨在协助研究人员对固件非分析,提取及逆向工程用处.简单易用,完全自动化脚本,并 ...
- Python进程池Pool
''' 进程池,启动一个进程就要克隆一份数据,假设父进程1G,那么启动进程开销很大 避免启动太多造成系统瘫痪,就有进程池,即同一时间允许的进程数量 ps:线程没有池,因为线程启动开销小,线程有类似信号 ...