Java对象的浅克隆和深克隆
为什么需要克隆
一、浅度克隆
浅度克隆对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象。
浅度克隆步骤:
1、实现java.lang.Cloneable接口
要clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的
clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出
CloneNotSupportedException异常。
2、重写java.lang.Object.clone()方法
JDK
API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。
观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解
释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public。
的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同
一个对象。
try {
return
super.clone();
} catch (CloneNotSupportedException e) {
return
null;
}
在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象
深度克隆步骤:
要克隆的类和类中所有非基本数据类型的属性对应的类
1、都实现java.lang.Cloneable接口
2、都重写java.lang.Object.clone()方法
try {
return
super.clone();
} catch (CloneNotSupportedException e) {
return
null;
}
try {
return
super.clone();
} catch (CloneNotSupportedException e) {
return
null;
}
三、使用对象序列化和反序列化实现深度克隆
所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。
Clone,如果使用序列化,不会超过10行代码就可以解决。
你可以通过添加serialVersionUID属性来解决这个问题(在Java序列化与反序列化学习(二):序列化接口说明 的标题三中有此说明)。如果你的类是个单例(Singleton)类,虽然我们多线程下的并发问题来控制单例,但是,是否允许用户通过序列化机制或者克隆来复制该类,如果不允许你需要谨慎对待该类的实现(让此类不用实现Serializable接口或Externalizable接口和Cloneable接口就行了)。
Attribute {
Product {
ByteArrayOutputStream byteOut = null;
ObjectOutputStream objOut = null;
ByteArrayInputStream byteIn = null;
ObjectInputStream objIn = null;
try {
将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
byteOut =
new ByteArrayOutputStream();
objOut =
new ObjectOutputStream(byteOut);
objOut.writeObject(this);
byteIn =
new ByteArrayInputStream(byteOut.toByteArray());
objIn =
new ObjectInputStream(byteIn);
return
(ContretePrototype) objIn.readObject();
} catch (IOException e) {
throw new
RuntimeException("Clone Object failed in IO.",e);
} catch (ClassNotFoundException e) {
throw new
RuntimeException("Class not found.",e);
} finally{
try{
byteIn = null;
byteOut = null;
if(objOut != null)
objOut.close();
if(objIn != null)
objIn.close();
}catch(IOException e){
}
}
BeanUtils、PropertyUtils,Spring BeanUtils,Cglib
BeanCopier)都是相当于克隆中的浅克隆。
BeanUtils
采用反射实现
Spring: void
copyProperties(Object source, Object target,String[]
ignoreProperties)
Apache:void copyProperties(Object dest, Object
orig)
Beancopier 采用动态字节码实现
cglib: BeanCopier
create(Class source, Class target,boolean
useConverter)
例如:
BeanCopier copier
=BeanCopier.create(stuSource.getClass(), stuTarget.getClass(),
false);
copier.copy(stuSource,
stuTarget, null);
15ms
4031ms
18514ms.
Java对象的浅克隆和深克隆的更多相关文章
- 如何复制一个java对象(浅克隆与深度克隆)
在项目中,有时候有一些比较重要的对象经常被当作参数传来传去,和C语言的值传递不同,java语言的传递都是引用传递,在任何一个地方修改了这个对象的值,就会导致这个对象在内存中的值被彻底改变.但是很多时候 ...
- Java对象的克隆和深浅问题
Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...
- 【Java一看就懂】浅克隆和深克隆
一.何为克隆 在Java的体系中,数据类型分为基本数据类型和引用数据类型. 基本数据类型包括byte,short,int,long,float,double,boolean,char 8种,其克隆可通 ...
- 深入理解Java的浅克隆与深克隆
前言 克隆,即复制一个对象,该对象的属性与被复制的对象一致,如果不使用Object类中的clone方法实现克隆,可以自己new出一个对象,并对相应的属性进行数据,这样也能实现克隆的目的. 但当对象属性 ...
- Java必备技能:clone浅克隆与深克隆
介绍 一直以来只知道Java有clone方法,该方法属于Object的,对于什么是浅克隆与深克隆就比较模糊了,现在就来补充学习一下. 概念 浅拷贝(浅克隆)复制出来的对象的所有变量都含有与原来的对象相 ...
- Java的浅克隆与深克隆
前言 克隆,即复制一个对象,该对象的属性与被复制的对象一致,如果不使用Object类中的clone方法实现克隆,可以自己new出一个对象,并对相应的属性进行数据,这样也能实现克隆的目的. 但当对象属性 ...
- java浅克隆和深克隆,序列化和反序列化实现深克隆(封装序列化和反序列化操作)
本篇博客内容: 一.浅克隆(ShallowClone)和深克隆(DeepClone) 二.序列化和反序列化实现深克隆 三.封装序列化和反序列化操作 ObjectOutputStream + 内存流By ...
- Java的浅克隆和深克隆
如何实现对象的克隆 (1)实现 Cloneable 接口并重写 Object 类中的 clone() 方法: (2)实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真 ...
- Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...
随机推荐
- Android记一次后台保活设计心得2018
首先我并不推荐也不喜欢手机应用通过各种手段后台保活,但是当产品经理确定一定以及肯定地提出了这个需求,活着应用有着必须常驻后台的理由,也就只有硬着头皮去与各个手机的后台管理机制做斗争了. 背景:因为开发 ...
- 使用微信JSSDK自定义微信分享标题、描述、和图标
最近做一个项目的时候用到微信的分享 ,实现定义分享标题,图片,了解到微信在发布JSSDK后,把包括自定义分享在内的众多网页服务接口进行了统一.如果要想自定义分享自己的网页信息给好友或朋友圈,就最好使用 ...
- [Linux] Proc 文件系统
转载自:http://linux.chinaunix.net/doc/2004-10-05/16.shtml#324lfindex0 目录: /proc --- 一个虚拟文件系统 加载 proc 文件 ...
- Java集合类理解
深入Java集合学习系列:http://zhangshixi.iteye.com/blog/674856 http://blog.csdn.net/shf4715/article/details/47 ...
- SQL精华应用
[精确到纳秒的时间函数] SYSDATETIME().SYSUTCDATETIME() ---- 精确程度取决于执行 SQL Server 实例的计算机硬件和 Windows 版本号 [ ...
- phpcms的后台网站直接访问正常,百度快照收录链接访问跳转到非法网站
问题: phpcms制作的网站直接访问正常,百度快照收录链接访问跳转到非法网站 百度快照收录网站域名,访问时自动跳转到一个非法网站 检查静态页index.html,index.php 网页内引用 ...
- 能显示git分支的终端提示配置
之前都是跟随潮流,安装zsh然后oh-my-zsh,选一个看起来顺眼的主题,一通瞎配置,很酷炫. 可是即使只有一个git插件,oh-my-zsh每次启动的时候都很慢,起码有好几秒,而且有时候zsh还会 ...
- centos/7/isos/x86_64 下载
为了节约有限的可用带宽. 不从mirror.centos.org下载iso映像 以下镜子应该可用的ISO映像: http://mirrors.aliyun.com/centos/7/isos/x86_ ...
- js 数组分解 解构
// ES5 a = list[0], rest = list.slice(1) // ES6 [a, ...rest] = list
- 模块化开发RequireJS之shim配置
一.shim requirejs使用AMD规范开发,若开发过程中加载非AMD规范js,需要使用requirejs的shim进行配置. shim配置语法为: //配置文件 requirejs.confi ...