为什么要克隆

为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象:

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()方法的更多相关文章

  1. Object类clone方法的自我理解

    网上搜帖: clone()是java.lang.Object类的protected方法,实现clone方法: 1)类自身需要实现Cloneable接口 2)需重写clone()方法,最好设置修饰符mo ...

  2. 方法object面试题分析:7JAVA中Object的clone方法详解-克隆-深克隆

    时间紧张,先记一笔,后续优化与完善.     每日一道理 翻开早已发黄的页张,试着寻找过去所留下的点点滴滴的足迹.多年前的好友似乎现在看来已变得陌生,匆忙之间,让这维持了多年的友谊变淡,找不出什么亲切 ...

  3. 为什么阿里Java手册推荐慎用 Object 的 clone 方法来拷贝对象

    图片若无法显示,可至掘金查看https://juejin.im/post/5d425230f265da039519d248 前言 在阿里Java开发手册中,有这么一条建议:慎用 Object 的 cl ...

  4. Java中clone方法的使用

    什么是clone 在实际编程过程中,我们常常要遇到这种情况:有一个对象object1,在某一时刻object1中已经包含了一些有效值,此时可能会需要一个和object1完全相同新对象object2,并 ...

  5. Java的Cloneable接口还有深浅复制

    我的小记录 首先语法上,搞清除,Java有个Cloneable接口,但这个接口是没有定义方法的. 那实现了这个接口有什么用呢? 再看Object类中,有个clone()方法,这个方法提供一个浅复制的功 ...

  6. 使用clone( )和Cloneable接口

    由Object类定义的绝大部分方法在本书其他部分讨论.而一个特别值得关注的方法是clone( ).clone( )方法创建调用它的对象的一个复制副本.只有那些实现Cloneable接口的类能被复制. ...

  7. Object.clone()方法与对象的深浅拷贝

    转载:[https://www.cnblogs.com/nickhan/p/8569329.html] 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Obj ...

  8. java Object对象的clone方法

    参考copy链接:http://blog.csdn.net/bigconvience/article/details/25025561 在看原型模式,发现要用到clone这个方法,以前和朋友聊过,没怎 ...

  9. 关于Java的Object.clone()方法与对象的深浅拷贝

    文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...

随机推荐

  1. ShellExecuteA

    //第三个参数是指令,可以是一个可执行程序(后面不能加参数).有默认打开方式的文件.路径.网址.各种协议地址如迅雷ftp邮箱ed2k等 MessageBoxA

  2. ubuntu如何傻瓜式安装eric6

    最近在搞PyQt5,听闻eric6是一个不错的IDE,但就是配置起来略蛋疼. 在网上搜到不少教程,都是要先编译安装Qt5, PyQt5, sip, qscintilla2, qscintilla2又分 ...

  3. 不支持C++11 decltype的噩耗

    前言:因为公司现在使用vs2008,所以很多c++11的新特性还未能使用,导致写了很多冤枉代码. 最初引擎的数学库非常简单,使用起来也不方便,例如: float FastLerp(const floa ...

  4. 硬浮点 VFP

    http://blog.chinaunix.net/uid-27875-id-3449290.html   编译器对VFP的支持一个浮点数操作最后是翻译成VFP指令,还是翻译成fpa,或者是softf ...

  5. 【Mail】搭建邮件服务器(LAMP+Postfix+Dovcot+PostfixAdmin+Roundcubemail)

    大纲 一.mail部署说明 二.安装准备 三.LMAP环境配置 四.配置postfixadmin 五.配置postfix 六.配置dovecot 七.测试SMTP和POP3服务 八.配置Roundcu ...

  6. 程序猿,千万别说你不了解Docker!

    放在两年前,你不认识Docker情有可原.但如果现在你还这么说,不好意思,我只能说你OUT了.你最好马上get起来,因为有可能你们公司很快就会引入Docker. 今天就和大家讨论讨论这个备受好评的应用 ...

  7. mvc+mysql+EF

    网上有很多关于EF在联机情况下利用nuget管理器安装的案例,我就讲一下脱机状况吧! 一.建立一个文件夹,例如D:/Packages 放入安装EF和mysql需要的包:EntityFramework. ...

  8. Jquery插件开发精品教程

    最开始接触jquery对他提供的各种插件总是十分有兴趣,但是总是不理解为什么这样写,从网络上查询了很久终于找到这篇文章,讲解的很详细,分享给大家. 要说jQuery 最成功的地方,我认为是它的可扩展性 ...

  9. 用Java导出为excel表格

    导出的是最基础的excel表格,没有任何样式. <input type="button" value="输出到Excel" onclick='output ...

  10. juery与表单中name="nodeName"引起的冲突

    引入jquery时,表单中如果有name="nodeName"的表单项,会有一些奇怪的冲突. 表单HTML代码如下: <form id="formAddEquipN ...