Java中对象的深克隆和浅克隆
2019独角兽企业重金招聘Python工程师标准>>>
浅克隆和深克隆的概念
浅克隆:被克隆的对象里的所有变量值都与原来的对象相同,而所有对其他对象的引用仍然指向原来的对象。简而言之,浅克隆仅仅克隆当前对象,而不克隆当前对象所引用的对象。
深克隆:被克隆的对象里的所有变量值都与原来的对象相同,那些引用其他对象的变量将指向被复制过的新对象,而不再是原来被引用的对象。简而言之,深克隆不仅克隆了当前对象,还把当前对象所引用的对象都复制了一遍。
Java中的clone()方法
Object类中的clone()方法属于浅克隆。它的工作原理是:先在内存中开辟一块和原始对象相同大小的空间,然后原样复制原始对象中的内容。对于基本数据类型,这样操作是没问题的。但对于非基本数据类型,由于它们所保存的仅仅是对象的引用,如果不进行更深层次的克隆,就会导致克隆后的对象引用和原始对象中相应的对象引用所指向的是同一个对象。
使用clone()方法实现浅克隆
在要克隆的类中实现Cloneable接口,覆盖Object类中的clone()方法,并声明为public。同时在clone()方法中,调用super.clone()返回克隆后的对象。请看以下代码:
class Professor {String name;int age;public Professor(String name, int age) {this.name = name;this.age = age;}
}class Student implements Cloneable {String name;int age;Professor professor;public Student(String name, int age, Professor professor) {this.name = name;this.age = age;this.professor = professor;}@Overrideprotected Student clone() throws CloneNotSupportedException {return (Student) super.clone();}
}public class CloneTutorial {public static void main(String[] args) throws CloneNotSupportedException {Professor professor = new Professor("Galler", 50);Student student1 = new Student("Tom", 18, professor);Student student2 = student1.clone();System.out.println("Before change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("student1's professor age = " + student1.professor.age);student2.professor.name = "Mary";student2.professor.age = 30;System.out.println();System.out.println("After change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("Student1's professor age = " + student1.professor.age);}
}
使用clone()方法实现深克隆
通过以上代码可以证明Java中的clone()方法是浅克隆,那应该如何实现更深层次的克隆呢?请看以下代码:
class Professor implements Cloneable {String name;int age;public Professor(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Professor clone() throws CloneNotSupportedException {return (Professor) super.clone();}
}class Student implements Cloneable {String name;int age;Professor professor;public Student(String name, int age, Professor professor) {this.name = name;this.age = age;this.professor = professor;}@Overrideprotected Student clone() throws CloneNotSupportedException {Student student = (Student) super.clone();student.professor = student.professor.clone();return student;}
}public class CloneTutorial {public static void main(String[] args) throws CloneNotSupportedException {Professor professor = new Professor("Galler", 50);Student student1 = new Student("Tom", 18, professor);Student student2 = student1.clone();System.out.println("Before change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("student1's professor age = " + student1.professor.age);student2.professor.name = "Mary";student2.professor.age = 30;System.out.println();System.out.println("After change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("Student1's professor age = " + student1.professor.age);}
}
在以上代码中,虽然通过在Student类中调用Professor类中覆盖的clone方法来对professor成员进行克隆从而实现了深克隆,但也由此可见,如果克隆类中的引用类型变量有多个的情况下,采用这种方式实现深克隆将会非常复杂。
使用对象序列化和反序列化实现深克隆(推荐)
把对象写到字节流里的过程是序列化(Serilization)的过程,而把对象从字节流中读出来的过程是反序列化(Deserialization)的过程。由于在Java 序列化的过程中,写在流里的是对象的一个拷贝,而原对象仍然在JVM里,所以可以利用这个原理来实现对对象的深克隆。请看以下代码:
class Professor implements Serializable {String name;int age;public Professor(String name, int age) {this.name = name;this.age = age;}
}class Student implements Serializable {String name;int age;Professor professor;public Student(String name, int age, Professor professor) {this.name = name;this.age = age;this.professor = professor;}public Student deepClone() throws Exception {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(this);ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);return (Student) objectInputStream.readObject();}
}public class CloneTutorial {public static void main(String[] args) throws Exception {Professor professor = new Professor("Galler", 50);Student student1 = new Student("Tom", 18, professor);Student student2 = student1.deepClone();System.out.println("Before change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("student1's professor age = " + student1.professor.age);student2.professor.name = "Mary";student2.professor.age = 30;System.out.println();System.out.println("After change student2's professor");System.out.println("Student1's professor name = " + student1.professor.name);System.out.println("Student1's professor age = " + student1.professor.age);}
}
总结
虽然使用Java的clone()方法实现浅克隆以及深克隆更加直观,但是针对每一个需要克隆的类都必须单独实现一个clone()方法,导致其扩展性并不好。而使用对象序列化与反序列化来实现深克隆,能使代码更简洁,更通用。此处推荐使用后者。
转载于:https://my.oschina.net/zhaojia/blog/735432
Java中对象的深克隆和浅克隆相关推荐
- Java中对象的深复制(深克隆)和浅复制(浅克隆)介绍
1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...
- Java中对象的储存区
文章目录 1 两个重要的问题 2 C语言中数据的存储区 3 Java中对象的储存区 4 Java为什么采用动态内存分配? 4 为什么基本类型是特例? 1 两个重要的问题 对象的数据位于何处? 如何控制 ...
- Java中对象的实例化顺序
文章目录 1 Java中对象的实例化顺序 1 Java中对象的实例化顺序 继承后的初始化顺序: 静态成员包括静态构造代码块,初始化顺序跟书写顺序有关.
- 浅析Java中对象的创建与对象的数据类型转换
这篇文章主要介绍了Java中对象的创建与对象的数据类型转换,是Java入门学习中的基础知识,需要的朋友可以参考下 Java:对象创建和初始化过程 1.Java中的数据类型 Java中有3个数据 ...
- Java中对象的三种状态
转载自 Java中对象的三种状态 Java中的对象的三种状态是和垃圾回收紧密相关的,因此有必要深究. 状态一:可触及态:从根节点开始,可以搜索到这个对象,也就是可以访问到这个对象,也有人将其称为可 ...
- Java中对象和引用的理解
2019独角兽企业重金招聘Python工程师标准>>> 偶然想起Java中对象和引用的基本概念,为了加深下对此的理解和认识,特地整理一下相关的知识点,通过具体实例从两者的概念和区别两 ...
- java中的的一些生命周期,Java中对象的生命周期
Java中对象的生命周期 (1) 对象生命周期的开始 对象生命周期开始时,需要为对象分配内存,并且初始化它的实例变量: 对象生命周期结束 Java虚拟机的垃圾回收线程回收对象的内存. (2) 创建一个 ...
- [转载] java中对象作为参数传递给一个方法,到底是值传递,还是引用传递
参考链接: 用Java传递和返回对象 看完绝对清晰~ java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? pdd:所谓java只有按值传递:基本类型 值传递:引用类型,地址值传递,所 ...
- Java中对象的串行化(Serialization)和transient关键字
Java中对象的串行化(Serialization)和transient关键字 前言: 该篇文章参考自网上资料,但是部分内容经过笔者更改,因此算作原创吧,原文地址: http://www.golden ...
最新文章
- tomcat8配置tomcat-users.xml不生效
- Spring-AOP基础知识
- mingw编译wxwidgets
- boost::graph模块实现二分图算法的测试程序
- 成为自信的node.js开发者(一)
- 如何将网页部署到maven_如何通过Rultor将Maven工件部署到CloudRepo
- C++编写简单的俄罗斯方块游戏
- python3+Neo4j+flask,汽车行业知识图谱项目实战
- C++多线程——_beginthread()和_beginthreadex
- 《C++ Primer 5th》知识点总结练习题解
- 基于simulink的风能/光伏发电系统仿真
- YOLOv3在Intel Realsense上的Python实现(未实现)
- 模仿探探(百合网,珍爱网)卡片左右滑动效果,滑动流畅,卡片view无限重生
- Java零散知识点XXXXXXXXX
- Unity3D中文视频教程【超清+精选】
- 阅读text2sql论文《RAT-SQL: Relation-Aware Schema Encoding and Linking for Text-to-SQL Parsers》
- 5-Redis 高可用篇:你管这叫 Sentinel 哨兵集群原理(码哥)
- 移动游戏开发商50强(世界)
- 电话营销机器人具体是怎么运行的呢?
- 百度文库怎么引流,做百度文库有哪些技巧?
热门文章
- 改工作空间_打拼六年换的新房,装修花了17万,飘窗改柜子很实用,谁见过?...
- webstorm前端调用后端接口_一篇前端同学对后端接口的吐槽
- android javamail获取邮件太多太慢_java 实现 email 邮件发送最简单优雅的方式(网易 163 为例)
- 正则表达式中的字符类
- 天翼云认证--大纲介绍
- Spring单例的线程安全性
- 笔记-知识产权与标准化知识-GB/T9385-2006计算机软件文档编制规范
- linux下几种运行后台任务的方法
- 信息系统项目管理师-常用英文术语整理
- 若依前后端分离版怎样修改主页面和浏览器上的图标和标题