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

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指向内存堆中同一个对象。如图:

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

是否记得万类之王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 }

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

java复制一个对象_Java中对象的复制相关推荐

  1. java字符串深克隆_Java中对象的深复制(深克隆)和浅复制(浅克隆)之序列化...

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. 举 ...

  2. java 释放一个对象_JAVA中销毁一个对象的方法

    方法一:垃圾回收器 垃圾回收器是Java平台中用的最频繁的一种对象销毁方法.垃圾回收器会全程侦测Java应用程序的运行情况.当反先有些对象成为垃圾时,垃圾回收器就会销毁这些对象,并释放这些对象所占用的 ...

  3. java 初始化顺序_Java中对象初始化顺序的详细介绍

    前言 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.最近我发现了一个有趣的问题,这个问题的答案乍一看下骗过了我的眼睛.看一下这三个类: package com ...

  4. java声明一个对象_Java声明对象

    当你创建一个类时,你创建了一种新的数据类型.你可以使用这种类型来声明该种类型的对象.然而,要获得一个类的对象需要两步.第一步,你必须声明该类类型的一个变量,这个变量没有定义一个对象.实际上,它只是一个 ...

  5. Java中对象的复制

    假如说你想复制一个简单变量.很简单: 1 int n = 5; 2 int m = n; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,doub ...

  6. java 复制一个对象_Java如何完全复制一个对象

    Java里的clone分为: ** A:浅复制(浅克隆): **浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. B:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍. Java中对 ...

  7. php如何复制一个对象,PHP中的对象复制及__clone() 函数

    在PHP中, 对象间的赋值操作实际上是引用操作 (事实上,绝大部分的编程语言都是如此! 主要原因是内存及性能的问题) , 比如 : [code lang="php"] class ...

  8. java类怎么删除对象_java中对象的生成使用和删除

    请教大神,在java里,对象生成后,如何删除对象呢?请教大神,在java里,对象生成后,如何删除对象呢? 对象状态由JVM自动管理,GC线程自动回收无用对象,无需也不能自己删除对象. 请问在JAVA中 ...

  9. php 克隆对象,php中对象的复制与克隆

    * 对象的复制与克隆 * 1.默认情况下,对象是引用传递(实际上是对象标识符的复制,后面会详细说) * 2.也就是说二个对象变量实际上是引用的是同一个对象 * 3.如果要创建一个新的对象,必须使用cl ...

最新文章

  1. RPC调用框架比较分析--转载
  2. spark代码连接hive_spark SQL学习(spark连接hive)
  3. 使用计算机教学的意义,信息技术在教学中的作用
  4. Eclipse安装后启动出现error:could not create the java machine.
  5. matlab快速将几幅图片放在一幅图片
  6. JS 输入框智能提示
  7. linux 新老软件切换,Linux下非常重要的软件切换命令
  8. AWVS13破解docker一键安装
  9. Linux C语言 vim编辑器 使用 sqlite3数据库 makefile 的网络编程 qq 聊天室项目
  10. 服务器基线扫描修复,怎么对服务器进行基线和漏洞扫描
  11. 机器学习领域几种距离度量方法metric详解
  12. 苹果终于入伙 WebRTC,新一代移动 Web 应用爆发路上还有哪些坑?
  13. 我所理解的JS ~~运算符
  14. Nape实现坐标旋转角度回弹
  15. Document-Level Relation Extraction with Adaptive Thresholding and Localized Context Pooling
  16. 【Flink】学习笔记-20200302更新
  17. git 基本命令总结
  18. OpenVINO 2021r4.1 - 瞎搞YOLOV5 模型转换,INT8量化及C++推理实现
  19. SpO2、SaO2、PaO2、低氧血症概念及标准的总结
  20. PHP怎么做成Qq空间相册,qq空间如何上传本地视频 相片制作视频传到QQ空间

热门文章

  1. 【codevs2488】绿豆蛙的归宿
  2. 【42.59%】【codeforces 602A】Two Bases
  3. 《转》不要过打折的生活,当你发现这些你有了,说明你开始成熟了
  4. 特老的文章:三层应该怎么划分。不知大家还有用否
  5. 操作系统学习笔记-2.1.3进程控制
  6. 项目:NMEA2000的数据格式解析
  7. linux的常用操作——查看和修改文件权限
  8. 牛客21783 牛牛的星际旅行
  9. 【剑指offer】面试题31:栈的压入、弹出序列(Java)
  10. Leetcode--17.电话号码的字母组合