使用场景:

在日常的编程过程 中,经常会遇到,有一个对象OA,在某一时间点OA中已经包含了一些有效值 ,此时可能会需一个和OA完全相对的新对象OB,并且要在后面的操作中对OB的任何改动都不会影响到OA的值,也就是OA与Ob是需要完全两个独立的对象。

但OB的初始值是由对象OA确定的。在JAVA语言中,用普通的赋值语句是满足不了需求的。使用对象的clone()方法是实现克隆的最简单、也是最高效的手段。

Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。 实现克隆可以用深拷贝和浅拷贝来实现。

深拷贝和浅拷贝的基本概念的理解:

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象

通过实例看深拷贝和浅拷贝的实现和不同:

浅拷贝

class AddressNew implementsCloneable {privateString add;publicString getAdd() {returnadd;

}public voidsetAdd(String add) {this.add =add;

}public Object clone() throwsCloneNotSupportedException{return super.clone();

}

}public class StudentNew implementsCloneable{private intnumber;privateString name;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}privateAddressNew addr;publicAddressNew getAddr() {returnaddr;

}public voidsetAddr(AddressNew addr) {this.addr =addr;

}public intgetNumber() {returnnumber;

}public void setNumber(intnumber) {this.number =number;

}public Object clone() throwsCloneNotSupportedException {return super.clone();

}

}public classJavaShallowCopy {public static void main(String [] args) throwsException{

AddressNew addr= newAddressNew();

addr.setAdd("杭州市");

StudentNew stu1= newStudentNew();

stu1.setNumber(123);

stu1.setName("s1");

stu1.setAddr(addr);

StudentNew stu2=(StudentNew)stu1.clone();

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

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

System.out.println(stu1);

System.out.println(stu2);

addr.setAdd("西湖区");//stu1.setNumber(20);//stu2.setName("s2");

System.out.println("学生1:" + stu1.getName() + ",地址:" +stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getName() + ",地址:" +stu2.getAddr().getAdd());

}

}

运行结果:

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

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

com.songidea.StudentNew@133314b

com.songidea.StudentNew@b1bc7ed

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

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

从运行结果来看,stu1,stu2的解是2个不同的对象了,但是在改变了,addr的对象的地址之后,stu1,stu2的2个对象的引用对象addr的值都改变了,也就是说stu1和stu2的addr对象引用的是同一个地址,这个不是我们想要的结果,在实际的开发工作中这一块一定要特别注意,使用不当可能会使业务功能或数据造成错误或混乱,所以这个拷贝只是实现在浅拷贝,那么从我们需要的场景看需要实现深拷贝才能达到我们想要的结果,下面会通过实例来看深拷贝的2种不同的实现。

深拷贝:

class Address implementsCloneable {privateString add;publicString getAdd() {returnadd;

}public voidsetAdd(String add) {this.add =add;

}

@OverridepublicObject clone() {

Address addr= null;try{

addr= (Address)super.clone();

}catch(CloneNotSupportedException e) {

e.printStackTrace();

}returnaddr;

}

}public class Student implementsCloneable{private intnumber;privateString name;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}privateAddress addr;publicAddress getAddr() {returnaddr;

}public voidsetAddr(Address addr) {this.addr =addr;

}public intgetNumber() {returnnumber;

}public void setNumber(intnumber) {this.number =number;

}

@OverridepublicObject clone() {

Student stu= null;try{

stu= (Student)super.clone(); //浅复制

}catch(CloneNotSupportedException e) {

e.printStackTrace();

}

stu.addr= (Address)addr.clone(); //深度复制

returnstu;

}

}public classjavaDeepCopy {public static voidmain(String args[]) {

Address addr = new Address();

addr.setAdd("杭州市");

Student stu1 = new Student();

stu1.setNumber(123);

stu1.setName("s1");

stu1.setAddr(addr);

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

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

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

System.out.println(stu1);

System.out.println(stu2);

addr.setAdd("西湖区");

stu1.setNumber(20);

System.out.println("学生1:" + stu1.getName() + ",地址:" + stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getName() + ",地址:" + stu2.getAddr().getAdd());

} }

运行结果:

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

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

com.songidea.Student@133314b

com.songidea.Student@b1bc7ed

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

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

从运行结果来看,stu1,stu2的解是2个不同的对象了,在改变了addr的对象的地址之后,stu1,stu2的2个对象的引用对象addr的值只有stu1r 改变了,也就是说stu1和stu2的addr对象引用的不是同一个地址,这个是我们想要的结果所以这个拷贝只是实现在浅拷贝,那么从我们需要的场景看,这种方式实现了深拷,达到了我们想要的结果,下面会通过实例来看深拷贝的另一种实现:通过序例化来实现深拷贝。

深拷贝序列化的实现:

class AddressSerial implementsSerializable {privateString add;publicString getAdd() {returnadd;

}public voidsetAdd(String add) {this.add =add;

}

}public class StudentSerial implementsSerializable{private intnumber;privateString name;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}privateAddressSerial addr;publicAddressSerial getAddr() {returnaddr;

}public voidsetAddr(AddressSerial addr) {this.addr =addr;

}public intgetNumber() {returnnumber;

}public void setNumber(intnumber) {this.number =number;

}public Object clone() throwsCloneNotSupportedException {return super.clone();

}public Object deepClone() throwsIOException,OptionalDataException,ClassNotFoundException{

ByteArrayOutputStream bo=newByteArrayOutputStream();

ObjectOutputStream oo=newObjectOutputStream(bo);

oo.writeObject(this);

ByteArrayInputStream bi=newByteArrayInputStream(bo.toByteArray());

ObjectInputStream oi=newObjectInputStream(bi);returnoi.readObject();

}

}public classjavaDeepCopySreial {public static void main(String [] args) throwsException{

AddressSerial addr= newAddressSerial();

addr.setAdd("杭州市");

StudentSerial stu1= newStudentSerial();

stu1.setNumber(123);

stu1.setName("s1");

stu1.setAddr(addr);

StudentSerial stu2=(StudentSerial)stu1.deepClone();

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

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

System.out.println(stu1);

System.out.println(stu2);

addr.setAdd("西湖区");//stu1.setNumber(20);//stu2.setName("s2");

System.out.println("学生1:" + stu1.getName() + ",地址:" +stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getName() + ",地址:" +stu2.getAddr().getAdd());

}

}

运行结果:

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

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

com.songidea.StudentSerial@1e80bfe8

com.songidea.StudentSerial@5e9f23b4

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

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

从运行的结果看序例化也达到了深拷贝的场景。

参考和阅读的几偏深拷贝浅拷贝的文章:

https://www.cnblogs.com/null00/archive/2010/12/14/2065088.html

https://www.cnblogs.com/xuanxufeng/p/6558330.html

https://blog.csdn.net/baiye_xing/article/details/71788741

java对象深克隆_JAVA中对象的克隆及深拷贝和浅拷贝相关推荐

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

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

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

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

  3. java对象数组_Java中对象数组的使用方法详解

    本文实例讲述了Java中对象数组的使用方法.分享给大家供大家参考,具体如下: 一 点睛 对象可以用数组来存放,通过下面两个步骤来实现. 1 声明以类为数据类型的数组变量,并用new分配内存空间给数组. ...

  4. java中的对象数组_Java中对象数组的使用方法详解

    本文实例讲述了java中对象数组的使用方法.分享给大家供大家参考,具体如下: 一 点睛 对象可以用数组来存放,通过下面两个步骤来实现. 1 声明以类为数据类型的数组变量,并用new分配内存空间给数组. ...

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

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

  6. java html对象属性_java中对象属性可以是另外一个对象或对象的参考

    7.对象的属性可以是另外一个对象或对象的参考 通过这种方法可以迅速构建一个比较大的系统. class Motor { Light[] lights; Handle left, right; KickS ...

  7. java中对象排序_java中 对象的排序

    1:排序类 package com.tixa.bad.customer.util; import java.util.ArrayList; import java.util.Collections; ...

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

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

  9. java的对象是什么意思_Java中对象和对象引用的区别,引用、指向是什么意思

    Java的变量分为两大类:基本数据类型和引用数据类型. 其中基本类型变量有四类8种:byte short int long float double char boolean,除了8种基本数据类型变量 ...

最新文章

  1. 淺談Raid Cache Memory上應用的問題和實踐
  2. MSN工具条不兼容IE7
  3. java课后习题_【整理】java私塾教程课后习题
  4. final 实例域+final类+final方法(阻止继承)
  5. [expimp]imp导入笔记
  6. c9500堆叠配置_用C ++堆叠
  7. My first App Encrypt Wheel is Ready to Download!
  8. centos出现“FirewallD is not running”
  9. Redis RU330课程 Redis Security 第3周学习笔记
  10. 硬盘显示无法访问由于IO设备错误的文件找到办法
  11. Java实现图片水印
  12. 2019/04/11 网易互娱游戏研发工程师实习生一面面经(Offer到手)
  13. 程序员突然倒地!中软国际回应称系低血糖引发
  14. QT小游戏(五子棋)
  15. 相控非绝缘技术为何是黄金微针效用至高点?深度剖析相控射频微针差异
  16. 2019年终总结--回顾过去,展望未来
  17. Chalk-控制台输出着色Nodejs库
  18. 学校食堂外卖APP开发模板
  19. JAVA学习之前端知识掌握Day002
  20. linux系统下查看图片尺寸的命令

热门文章

  1. Apache Flink 在京东的实践与优化
  2. 阿里云机器学习怎么玩?这本新手入门指南揭秘了!
  3. 阿里云峰会|数据库也能自动驾驶?DAS全天候给你保驾护航!
  4. MySQL实战—更新过程
  5. 阿里云2020上云采购季,你适合买什么云产品?
  6. GMTC2019|闲鱼-基于Flutter的架构演进与创新
  7. 不断迭代,严苛细节,最终性能如何满足? 基于ELK的大数据平台实践分享
  8. 全新一代人工智能计算引擎MaxCompute杭州开服,强化阿里云大数据能力,比肩谷歌微软...
  9. 【干货合集】看完这些干货,再说你因为“怕蛇”,所以学不好Python!
  10. 北森iTalentX 3.0:聚焦场景一体,开启HR全面数字化时代