Cloneable接口和Object的clone()方法
为什么要克隆
为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象:
- public class SimpleObject implements Cloneable
- {
- private String str;
- public SimpleObject()
- {
- System.out.println("Enter SimpleObject.constructor()");
- }
- public String getStr()
- {
- return str;
- }
- public void setStr(String str)
- {
- this.str = str;
- }
- public Object clone() throws CloneNotSupportedException
- {
- return super.clone();
- }
- }
现在我写一段程序:
- public static void main(String[] args)
- {
- SimpleObject so0 = new SimpleObject();
- so0.setStr("111");
- System.out.println("so0.getStr():" + so0.getStr());
- SimpleObject so1 = so0;
- so1.setStr("222");
- System.out.println("so0.getStr():" + so0.getStr());
- System.out.println("so1.getStr():" + so1.getStr());
- }
运行结果其实很明显:
- so0.getStr():111
- so0.getStr():222
- so1.getStr():222
Java底层使用C/C++实现的,"="这个运算符,如果左右两边都是对象引用的话,在Java中表示的将等号右边的引用赋值给等号左边的引用,二者指向的还是同一块内存,所以任何一个引用对内存的操作都直接反映到另一个引用上。
但是,现在我想拿这个so0的数据进行一些操作,不想改变原来so0中的内容,这时候就可以使用克隆了,它允许在堆中克隆出一块和原对象一样的对象,并将这个对象的地址赋予新的引用,这样,显然我对新引用的操作,不会影响到原对象。
当然,理解克隆,最好还是对Java内存区域有比较好的理解。
Cloneable接口和Object的clone()方法
Java中实现了Cloneable接口的类有很多,像我们熟悉的ArrayList、Calendar、Date、HashMap、Hashtable、HashSet、LinkedList等等。
还是那句话,对于不熟悉的接口、方法,第一反应一定是查询JDK API。
1、Cloneable接口
三句话总结:
(1)此类实现了Cloneable接口,以指示Object的clone()方法可以合法地对该类实例进行按字段复制
(2)如果在没有实现Cloneable接口的实例上调用Object的clone()方法,则会导致抛出CloneNotSupporteddException
(3)按照惯例,实现此接口的类应该使用公共方法重写Object的clone()方法,Object的clone()方法是一个受保护的方法
2、Object的clone()方法
创建并返回此对象的一个副本。对于任何对象x,表达式:
(1)x.clone() != x为true
(2)x.clone().getClass() == x.getClass()为true
(3)x.clone().equals(x)一般情况下为true,但这并不是必须要满足的要求
克隆实例
把上面例子的main函数修改一下:
- public static void main(String[] args) throws Exception
- {
- SimpleObject so0 = new SimpleObject();
- so0.setStr("111");
- SimpleObject so1 = (SimpleObject)so0.clone();
- System.out.println("so0 == so1?" + (so0 == so1));
- System.out.println("so0.getClass() == so1.getClass()?" + (so0.getClass() == so1.getClass()));
- System.out.println("so0.equals(so1)?" + (so0.equals(so1)));
- so1.setStr("222");
- System.out.println("so0.getStr():" + so0.getStr());
- System.out.println("so1.getStr():" + so1.getStr());
- }
看一下运行结果:
- Enter SimpleObject.constructor()
- so0 == so1?false
- so0.getClass() == so1.getClass()?true
- so0.equals(so1)?false
- so0.getStr():111
- so1.getStr():222
得到三个结论:
1、克隆一个对象并不会调用对象的构造方法,因为"Enter SimpleObject.constructor()"语句只出现了一次
2、符合JDK API的clone()方法三条规则
3、so1对于SimpleObject对象str字段的修改再也不会影响到so0了
浅克隆和深克隆
浅克隆(shallow clone)和深克隆(deep clone)反映的是,当对象中还有对象的时候,那么:
1、浅克隆,即很表层的克隆,如果我们要克隆对象,只克隆它自身以及它所包含的所有对象的引用地址
2、深克隆,克隆除自身对象以外的所有对象,包括自身所包含的所有对象实例
这两个概念应该很好理解,就不写代码了。多提一句,所有的基本数据类型,无论是浅克隆还是深克隆,都会进行原值克隆,毕竟它们都不是对象,不是存储在堆中的。
那其实Object的clone()方法,提供的是一种浅克隆的机制,如果想要实现对对象的深克隆,在不引入第三方jar包的情况下,可以使用两种办法:
1、先对对象进行序列化,紧接着马上反序列化出
2、先调用super.clone()方法克隆出一个新对象来,然后在子类的clone()方法中手动给克隆出来的非基本数据类型(引用类型)赋值,比如ArrayList的clone()方法:
- public Object clone() {
- try {
- ArrayList<E> v = (ArrayList<E>) super.clone();
- v.elementData = Arrays.copyOf(elementData, size);
- v.modCount = 0;
- return v;
- } catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError();
- }
- }
Cloneable接口和Object的clone()方法的更多相关文章
- Object类clone方法的自我理解
网上搜帖: clone()是java.lang.Object类的protected方法,实现clone方法: 1)类自身需要实现Cloneable接口 2)需重写clone()方法,最好设置修饰符mo ...
- 方法object面试题分析:7JAVA中Object的clone方法详解-克隆-深克隆
时间紧张,先记一笔,后续优化与完善. 每日一道理 翻开早已发黄的页张,试着寻找过去所留下的点点滴滴的足迹.多年前的好友似乎现在看来已变得陌生,匆忙之间,让这维持了多年的友谊变淡,找不出什么亲切 ...
- 为什么阿里Java手册推荐慎用 Object 的 clone 方法来拷贝对象
图片若无法显示,可至掘金查看https://juejin.im/post/5d425230f265da039519d248 前言 在阿里Java开发手册中,有这么一条建议:慎用 Object 的 cl ...
- Java中clone方法的使用
什么是clone 在实际编程过程中,我们常常要遇到这种情况:有一个对象object1,在某一时刻object1中已经包含了一些有效值,此时可能会需要一个和object1完全相同新对象object2,并 ...
- Java的Cloneable接口还有深浅复制
我的小记录 首先语法上,搞清除,Java有个Cloneable接口,但这个接口是没有定义方法的. 那实现了这个接口有什么用呢? 再看Object类中,有个clone()方法,这个方法提供一个浅复制的功 ...
- 使用clone( )和Cloneable接口
由Object类定义的绝大部分方法在本书其他部分讨论.而一个特别值得关注的方法是clone( ).clone( )方法创建调用它的对象的一个复制副本.只有那些实现Cloneable接口的类能被复制. ...
- Object.clone()方法与对象的深浅拷贝
转载:[https://www.cnblogs.com/nickhan/p/8569329.html] 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Obj ...
- java Object对象的clone方法
参考copy链接:http://blog.csdn.net/bigconvience/article/details/25025561 在看原型模式,发现要用到clone这个方法,以前和朋友聊过,没怎 ...
- 关于Java的Object.clone()方法与对象的深浅拷贝
文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...
随机推荐
- Flask备注三(Context)
Flask备注三(Context) Flask支持不同的应用场景下,对应不同的local context(本地上下文环境),用来提供当前环境下的资源.lcoal context和全局变量以及局部变量最 ...
- PTGM and APTM
1. 性能测试过程模型(PTGM) PTGM模型包括以下几个步骤: 测试前期的准备 测试工具的引入 测试计划 测试设计与开发 测试执行与管理 测试分析 测试前期准备:主要任务为保证系统稳定和建立合适的 ...
- vs快捷键visual studio
网上抄的.记录下来.没全试过!强大的VS,真的喜欢! Shift+Alt+Enter: 切换全屏编辑 Ctrl+B,T / Ctrl+K,K: 切换书签开关Ctrl+B,N / Ctrl+K,N: 移 ...
- UWP的拖拽功能
简单的拖拽实现: <Grid x:Name="G1" AllowDrop="True" DragEnter="G1_DragEnter" ...
- ORA-12543: TNS:destination host unreachable
在连接Oracle数据库时,如果使用Tnsnames.ora中配置的数据源名称有时会报 ORA-12543: TNS:destination host unreachable 异常,比如:在Tnsna ...
- Python处理json格式的数据文件(一些坑、一些疑惑)
这里主要说最近遇到的一个问题,不过目前只是换了一种思路先解决了,脑子里仍然有疑惑,只能怪自己太菜. 最近要把以前爬的数据用一下了,先简单的过滤一下,以前用scrapy存数据的时候为了省事也为了用一下它 ...
- 任务调度框架-Quartz.Net
使用Quartz.Net依赖于以下3个组件:Common.Logging.dll.Common.Logging.Core.dll.Quartz.dll 简单封装 using Quartz; using ...
- Android数据存储之SharedPreferences存储
安卓系统为应用提供了系统级的配置存储方案,它就是靠SharedPreferences接口来实现的,该接口存储的所有信息都是以名值对的形式保存,但其保存的数据类型也仅限于基本数据类型,如字符串.整形.布 ...
- React Native填坑之旅--Stateless组件
Stateless component也叫无状态组件.有三种方法可以创建无状态组件. 坑 一般一个组件是怎么定义的: 很久以前的方法: const Heading = createClass({ re ...
- WEB响应布局
[15/06月,15] em是相对长度单位.相对于当前对象内文本的字体尺寸.如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸.(引自CSS2.0手册) 任意浏览器的默认字体高都是1 ...