java复制一个对象_Java中对象的复制

假如说你想复制一个简单变量。很简单:

1 int n = 5;2 int m = n;

不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。但是如果你复制的是一个对象,情况就有些复杂了。

假设说我是一个beginner,我会这样写:

1 classStudent {2 private intnumber;3

4 public intgetNumber() {5 returnnumber;6 }7

8 public void setNumber(intnumber) {9 this.number =number;10 }11

12 }13 public classTest {14

15 public static voidmain(String args[]) {16

17 Student stu1 = newStudent();18 stu1.setNumber(12345);19 Student stu2 =stu1;20

21 System.out.println("学生1:" +stu1.getNumber());22 System.out.println("学生2:" +stu2.getNumber());23 }24 }

打印结果:

学生1:12345

学生2:12345

这里我们自定义了一个学生类,该类只有一个number字段。

我们新建了一个学生实例,然后将该值赋值给stu2实例。(Student stu2 = stu1;)

再看看打印结果,作为一个新手,拍了拍胸腹,对象复制不过如此,

难道真的是这样吗?

我们试着改变stu2实例的number字段,再打印结果看看:

1 stu2.setNumber(54321);2

3 System.out.println("学生1:" +stu1.getNumber());4 System.out.println("学生2:" + stu2.getNumber());

打印结果:

学生1:54321

学生2:54321

这就怪了,为什么改变学生2的学号,学生1的学号也发生了变化呢?

原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2,

这样,stu1和stu2指向内存堆中同一个对象。如图:

1357823538_3539.jpg

那么,怎样才能达到复制一个对象呢?

是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。

该方法的签名是:

protected native Object clone() throws CloneNotSupportedException;

因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。

要想对一个对象进行复制,就需要对clone方法覆盖。

一般步骤是(浅复制):

1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)

2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)

下面对上面那个方法进行改造:

1 class Student implementsCloneable{2 private intnumber;3

4 public intgetNumber() {5 returnnumber;6 }7

8 public void setNumber(intnumber) {9 this.number =number;10 }11

12 @Override13 publicObject clone() {14 Student stu = null;15 try{16 stu = (Student)super.clone();17 }catch(CloneNotSupportedException e) {18 e.printStackTrace();19 }20 returnstu;21 }22 }23 public classTest {24

25 public static voidmain(String args[]) {26

27 Student stu1 = newStudent();28 stu1.setNumber(12345);29 Student stu2 =(Student)stu1.clone();30

31 System.out.println("学生1:" +stu1.getNumber());32 System.out.println("学生2:" +stu2.getNumber());33

34 stu2.setNumber(54321);35

36 System.out.println("学生1:" +stu1.getNumber());37 System.out.println("学生2:" +stu2.getNumber());38 }39 }

打印结果:

学生1:12345

学生2:12345

学生1:12345

学生2:54321

如果你还不相信这两个对象不是同一个对象,那么你可以看看这一句:

System.out.println(stu1 == stu2); //false

上面的复制被称为浅复制(Shallow Copy),还有一种稍微复杂的深度复制(deep copy):

我们在学生类里再加一个Address类。

1 classAddress {2 privateString add;3

4 publicString getAdd() {5 returnadd;6 }7

8 public voidsetAdd(String add) {9 this.add =add;10 }11

12 }13

14 class Student implementsCloneable{15 private intnumber;16

17 privateAddress addr;18

19 publicAddress getAddr() {20 returnaddr;21 }22

23 public voidsetAddr(Address addr) {24 this.addr =addr;25 }26

27 public intgetNumber() {28 returnnumber;29 }30

31 public void setNumber(intnumber) {32 this.number =number;33 }34

35 @Override36 publicObject clone() {37 Student stu = null;38 try{39 stu = (Student)super.clone();40 }catch(CloneNotSupportedException e) {41 e.printStackTrace();42 }43 returnstu;44 }45 }46 public classTest {47

48 public static voidmain(String args[]) {49

50 Address addr = newAddress();51 addr.setAdd("杭州市");52 Student stu1 = newStudent();53 stu1.setNumber(123);54 stu1.setAddr(addr);55

56 Student stu2 =(Student)stu1.clone();57

58 System.out.println("学生1:" + stu1.getNumber() + ",地址:" +stu1.getAddr().getAdd());59 System.out.println("学生2:" + stu2.getNumber() + ",地址:" +stu2.getAddr().getAdd());60 }61 }

打印结果:

学生1:123,地址:杭州市

学生2:123,地址:杭州市

乍一看没什么问题,真的是这样吗?我们在main方法中试着改变addr实例的地址。

1 addr.setAdd("西湖区");2

3 System.out.println("学生1:" + stu1.getNumber() + ",地址:" +stu1.getAddr().getAdd());4 System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());

打印结果:

学生1:123,地址:杭州市

学生2:123,地址:杭州市

学生1:123,地址:西湖区

学生2:123,地址:西湖区

这就奇怪了,怎么两个学生的地址都改变了?

原因是浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。

所以,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:

1 packageabc;2

3 class Address implementsCloneable {4 privateString add;5

6 publicString getAdd() {7 returnadd;8 }9

10 public voidsetAdd(String add) {11 this.add =add;12 }13

14 @Override15 publicObject clone() {16 Address addr = null;17 try{18 addr = (Address)super.clone();19 }catch(CloneNotSupportedException e) {20 e.printStackTrace();21 }22 returnaddr;23 }24 }25

26 class Student implementsCloneable{27 private intnumber;28

29 privateAddress addr;30

31 publicAddress getAddr() {32 returnaddr;33 }34

35 public voidsetAddr(Address addr) {36 this.addr =addr;37 }38

39 public intgetNumber() {40 returnnumber;41 }42

43 public void setNumber(intnumber) {44 this.number =number;45 }46

47 @Override48 publicObject clone() {49 Student stu = null;50 try{51 stu = (Student)super.clone(); //浅复制

52 }catch(CloneNotSupportedException e) {53 e.printStackTrace();54 }55 stu.addr = (Address)addr.clone(); //深度复制

56 returnstu;57 }58 }59 public classTest {60

61 public static voidmain(String args[]) {62

63 Address addr = newAddress();64 addr.setAdd("杭州市");65 Student stu1 = newStudent();66 stu1.setNumber(123);67 stu1.setAddr(addr);68

69 Student stu2 =(Student)stu1.clone();70

71 System.out.println("学生1:" + stu1.getNumber() + ",地址:" +stu1.getAddr().getAdd());72 System.out.println("学生2:" + stu2.getNumber() + ",地址:" +stu2.getAddr().getAdd());73

74 addr.setAdd("西湖区");75

76 System.out.println("学生1:" + stu1.getNumber() + ",地址:" +stu1.getAddr().getAdd());77 System.out.println("学生2:" + stu2.getNumber() + ",地址:" +stu2.getAddr().getAdd());78 }79 }

打印结果:

学生1:123,地址:杭州市

学生2:123,地址:杭州市

学生1:123,地址:西湖区

学生2:123,地址:杭州市

这样结果就符合我们的想法了。

最后我们可以看看API里其中一个实现了clone方法的类:

java.util.Date:

1 /**

2 * Return a copy of this object.3 */

4 publicObject clone() {5 Date d = null;6 try{7 d = (Date)super.clone();8 if (cdate != null) {9 d.cdate =(BaseCalendar.Date) cdate.clone();10 }11 } catch (CloneNotSupportedException e) {} //Won't happen

12 returnd;13 }

该类其实也属于深度复制。

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

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

相关文章

python判断是不是整数1002python判断是不是整数_Python判断一个数是不是为整数的方法...

Python判断一个数是不是为整数的方法发布时间:2020-07-08 15:44:30来源:亿速云阅读:84作者:清晨不懂Python判断一个数是不是为整数的方法?其实想解决这个问题也不难,下面让小编带着大家一起学习怎么去解决&…

spriteatlas 白屏的问题_Discuz白屏问题解决思

说到白屏,大家可能最先想到的就是dedecms了。Dedecms的白屏问题确实多,但是今天学习部小编要给大家介绍的是另一个大家耳熟能详的程序:discuz。说到discuz白屏,不少朋友感到非常头疼。为什么呢?Dz白屏的原因千奇百怪&a…

aix 超过一天的文件_Aix 6.1下 /dev/null 21 文件过大导致根目录爆满

原因:这是Aix6107系统下cas_agent软件的一个bug,原因是脚本写错了排查过程:1. 查看是哪个文件夹或哪个文件过大du -axg /|sort -rn|headls -ltr /dev/null*发现是 /dev/null 2>&1 过大,/dev只是存设备用的文件夹,文件都很…

HA集群实现原理 切换 JAVA_HA(一)高可用集群原理

高可用集群原理LVS集群DR模式简单的架构图如下所示:在上图的架构中,当Director服务器因软件、硬件、人为原因造成故障时,整个集群服务不可用,因此,需要再添加一台服务器实现Director服务高可用。整个系统的架构图如下所…

c语言指针没学可以学java_这是一篇来自刚脱离C语言的菜鸟所写下来的关于C语言之后转JAVA入门前期学习的感想...

/***My First writing*Name Li Tai Yue*Date 2018.12.14*/这是一篇来自刚脱离C语言的菜鸟所写下来的关于C语言之后转JAVA入门前期学习的感想。并且我也觉得这是一篇所有在校学习程序的小伙伴值得一看的文章。我想很多小伙帮都觉得敲代码是一件非常枯燥的事情,每天敲…

java outofmemory 处理_java.lang.OutOfMemoryError处理错误

原因: 常见的有以下几种:1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;3.代码中存在死循环或循环产生过多重复的对象实…

java queue 实现类 区别_Java集合11 (Queue)

java.util.Queue接口是java.util.Collection子接口。它代表一个有序的对象列表,就像List一样,但是它的使用有略微的区别。Queue被设计成从末端插入并且从头部删除的形式。Queue的实现类java.util.LinkedListjava.util.PriorityQueueLinkedList是一个非常…

实验四Java_《Java实验四》

实验4--附录三代码/*问题如下:编译如下代码,分析结果;将“注释这行”所在的行注释,再将注释的call2方法和main方法中的“StaticTest.call2(obj);”方去掉注释,再次编译,观察结果分析其原因。回答如下&#…

java是值调用_Java 只有值调用

在计算机科学中,参数传递的形式主要有以下2种: 值调用和引用调用,为了说明Java在传参过程中的参数传递方式,我们首先需要对上述中2种调用形式的定义做清晰的介绍定义现给出两者的定义:值调用(Call by Value): 指函数接收的是调用者提供的实参变量的值引用…

java 如何将数字倒置_每日一个小算法之整数中每位上的数字进行反转 20190810

题目要求:给出一个32位的有符号整数,你需要将这个整数中每位上的数字进行反转。示例 1:输入: 123输出: 321示例 2:输入: -123输出: -321示例 3:输入: 120输出: 21示例 4:输入:9646324351输出: 0注意:假设我们的环境只能存储得下 3…

mysql 投票总排行_MySQL投票表,查找每个用户对条目的最新投票,并根据值进行计数...

[编辑:]我添加了值(1052,10,3,1290839091,1)以更好地解决问题,并且必须将“item_id”添加到提取最新投票的子查询中.好极了!最后一个stackoverflow问题,我实际上可以回答!我已经浏览了一个星期寻找短暂的东西;甜蜜的我的胡同.感谢有趣的SQL问…

java多态可以传匿名对象吗_Java复习笔记2--匿名类和多态

匿名类Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.pri…

java se 开发web程序_JDiy快速开发WEB之javaSE环境搭建-初级

大学的时候对web开发很感兴趣,对网页中的动画,对用户注册,对网页中表格填写等等都倍感兴趣。加之又有专业课程编程语言java,因此,对java web产生了浓厚的兴趣,再加之有北京圣思园 风中叶 大师的视频教程&am…

java apktoo_apktool.jar

apktool.jar是APKTOOL这个反编译工具必须用到的必备jar包,给大家提供最新的apktool.jar2.3.4,有需要的赶快下载吧!。相关软件软件大小版本说明下载地址apktool.jar是APKTOOL这个反编译工具必须用到的必备jar包,给大家提供最新的ap…

Java 内存 关系_JVM和Linux之间的详细内存关系

JVM和Linux之间的详细内存关系在一些具有8g物理内存的服务器上,主要运行Java服务。系统内存分配如下:Java服务的JVM堆大小设置为6g,监视过程大约需要600m,Linux本身使用大约800m。从表面上看,物理记忆应该足够&#xf…

java遍历删除原理,Java 垃圾回收机制实现原理

一、垃圾回收机制的意义Java语言中一个显著的特点就是引入了垃圾回收机制,使c程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有“作用域”的概念&…

matlab简易编程,MATLAB简单编程

本帖最后由 wanggh 于 2016-12-5 14:47 编辑用数值差分、SOR迭代法求雷诺方程和用牛顿迭代法求解轴向柱塞泵滑靴副压力场的算法,%油膜厚度场、压力场迭代 MATLAB只认弧度制,不认角度制clear all; % (60rpm1rad/s)wg1000; %1000…

php删除字段某个字段,php数如何组删除某个字段

【摘要】PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。下面是php数如何组删除某个字段,让我们一起…

php重复点击按钮无效,完美解决UIButton按钮重复点击、多次响应的问题

最近测试老跑过来提bug,说按钮可以点好几次,然后蹦出来好几个一样的界面出来,解决了一个地方,其他地方也会冒出一样的问题来,仔细一想,还是要从根本上解决问题,于是想了几个方法:1.添…

matlab画地震复杂模型,基于MATLAB的地震正演模型实现

总 第 237 期2009 年 第 7 期计 算 机 与 数 字 工 程 37 7132  基 于 L 地 震 正 演 模 型 实 现 3贾 跃 玮 1)   杨   锐 2)(中 国 地 质 大 学 地 下 信 息 探 测 技 术 与 仪 器 教 育 部 重 点 实 验 室 1)   北 京   100083)(川 庆 钻 探 工 程 有 限 公 司 地 质 …