当前位置: 首页 > 编程日记 > 正文

java的深度克隆

原文:http://blog.csdn.net/randyjiawenjie/article/details/7563323
javaobjectinterfacestringclassexception

先做个标记

http://www.iteye.com/topic/182772

http://www.blogjava.net/jerry-zhaoj/archive/2009/10/14/298141.html

关于super.clone的理解

http://hi.baidu.com/%BB%AA%CF%C4%D1%A7%C9%FA%C1%AA%C3%CB/blog/item/7d70a43842622832b8998f86.html

http://tieba.baidu.com/p/938267457

http://topic.csdn.net/u/20080326/09/a48470f3-f2c2-43c4-af56-fa8ffc12b629.html

http://www.iteye.com/topic/1113790

如何查看JDK源码
http://hi.baidu.com/koflance/blog/item/07809915d6f70e5cf3de32dd.html

http://www.iteye.com/topic/1113790

java对象的克隆步骤:

1.类需要实现Cloneable接口

2 覆盖clone方法,调用super.clone即可。如果是复合类型,如数组,集合类,还需要继续clon下去。

类A1只含有原生类型的属性,A2、A3类含有复合类型的属性,实现起来要clone到底,不然只会拷贝一个引用,从而实现浅拷贝(影子拷贝),实际上只有一个堆对象。两个引用实际上指向了一个对象。

A1的实现

[java] view plaincopy
  1. public class A1 implements Cloneable {
  2. public int age;
  3. public Object clone() {
  4. A1 o = null;
  5. try {
  6. o = (A1) super.clone();
  7. catch (CloneNotSupportedException e) {
  8. e.printStackTrace();
  9. }
  10. return o;
  11. }
  12. Object o = new Object();
  13. }

A2的实现:

[java] view plaincopy
  1. public class A2 implements Cloneable {
  2. public String[] name;
  3. public Object clone() {
  4. A2 o = null;
  5. try {
  6. o = (A2) super.clone();
  7. o.name = (String[]) name.clone();
  8. catch (CloneNotSupportedException e) {
  9. e.printStackTrace();
  10. }
  11. return o;
  12. }
  13. public A2() {
  14. name = new String[2];
  15. }
  16. }
A3是最复杂的

[java] view plaincopy
  1. package com.tmall;
  2. import java.util.Vector;
  3. public class A3 implements Cloneable {
  4. public String name[];
  5. public Vector<B> claB;
  6. public A3() {
  7. name = new String[2];
  8. claB = new Vector<B>();
  9. }
  10. public Object clone() {
  11. A3 o = null;
  12. try {
  13. o = (A3) super.clone();
  14. o.name = (String[]) name.clone();// 深度clone
  15. o.claB = new Vector<B>();// 将clone进行到底
  16. for (int i = 0; i < claB.size(); i++) {
  17. B temp = (B) claB.get(i).clone();// 当然Class B也要实现相应clone方法
  18. o.claB.add(temp);
  19. }
  20. catch (CloneNotSupportedException e) {
  21. e.printStackTrace();
  22. }
  23. return o;
  24. }
  25. }

其中B类的定义:

[java] view plaincopy
  1. public class B {
  2. public int age;
  3. public Object clone() {
  4. B o = null;
  5. try {
  6. o = (B) super.clone();
  7. catch (CloneNotSupportedException e) {
  8. e.printStackTrace();
  9. }
  10. return o;
  11. }
  12. }

两个测试方法:

[java] view plaincopy
  1. public static void testA1(){
  2. A1 a11 = new A1();
  3. A1 a12 = (A1)a11.clone();
  4. a11.age = 10;
  5. a12.age = 20;
  6. System.out.println(a11.age);
  7. System.out.println(a12.age);
  8. }
  9. public static void testA2(){
  10. A2 a1=new A2();
  11. a1.name[0]="a";
  12. a1.name[1]="1";
  13. A2 a2=(A2)a1.clone();
  14. a2.name[0]="b";
  15. a2.name[1]="1";
  16. System.out.println("a1.name="+a1.name);
  17. System.out.println("a1.name="+a1.name[0]+a1.name[1]);
  18. System.out.println("a2.name="+a2.name);
  19. System.out.println("a2.name="+a2.name[0]+a2.name[1]);
  20. }

运行结果,可以知道成功实现了深拷贝。

进一步研究:

1  . 翻阅cloneable接口的源码,发现是一个空接口,啥都没有。

[java] view plaincopy
  1. package java.lang;
  2. /**
  3.  * A class implements the <code>Cloneable</code> interface to 
  4.  * indicate to the {@link java.lang.Object#clone()} method that it 
  5.  * is legal for that method to make a 
  6.  * field-for-field copy of instances of that class. 
  7.  * <p>
  8.  * Invoking Object's clone method on an instance that does not implement the 
  9.  * <code>Cloneable</code> interface results in the exception 
  10.  * <code>CloneNotSupportedException</code> being thrown.
  11.  * <p>
  12.  * By convention, classes that implement this interface should override 
  13.  * <tt>Object.clone</tt> (which is protected) with a public method.
  14.  * See {@link java.lang.Object#clone()} for details on overriding this
  15.  * method.
  16.  * <p>
  17.  * Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
  18.  * Therefore, it is not possible to clone an object merely by virtue of the
  19.  * fact that it implements this interface.  Even if the clone method is invoked
  20.  * reflectively, there is no guarantee that it will succeed.
  21.  *
  22.  * @author  unascribed
  23.  * @version 1.17, 11/17/05
  24.  * @see     java.lang.CloneNotSupportedException
  25.  * @see     java.lang.Object#clone()
  26.  * @since   JDK1.0
  27.  */
  28. public interface Cloneable {
  29. }
在这篇帖子中对这个问题就行了讨论

主题:我发现了一个悖论

2.

clone方法的错误使用。

在不止一篇帖子里面,错误地使用了clone这个方法。

如这里:主题:java clone方法使用详解

作者是这样调用clone方法的:

[java] view plaincopy
  1. A a1=new A();
  2. A a2=new A();     **
  3. a2=(A)a1.clone();
其实做一次实验就可以知道,**行是多余的。

[java] view plaincopy
  1. A1 a11 = new A1();
  2. A1 a12 = (A1) a11.clone();
  3. A1 a13 = new A1();
  4. System.out.println("a11的地址是" + a11);
  5. System.out.println("a12的地址是" + a12);
  6. System.out.println("a13的地址是" + a13);
  7. a13 = (A1) a11.clone();
  8. System.out.println("a13的地址是" + a13);

我的电脑运行结果是

a11的地址是com.tmall.A1@c17164
a12的地址是com.tmall.A1@1fb8ee3
a13的地址是com.tmall.A1@61de33
a13的地址是com.tmall.A1@14318bb

说明a12克隆成功;

[java] view plaincopy
  1. A1 a12 = (A1) a11.clone();
是没有问题的。

反而实现new 一个对象如a13,在调用clone()方法会多此一举:

[java] view plaincopy
  1. A1 a13 = new A1();
[java] view plaincopy
  1. a13 = (A1) a11.clone();

可以看到运行结果里面,a13的地址换了两次。第一次是new出来的新对象,第二次是克隆出来的新对象,两次地址都不等于那个被clone的对象a11。

我翻阅了《effectice java》的条款11,“谨慎地覆盖clone”。作者Joshua Bloch(可是google的首席java工程师)第三段写道:

“如果实现cloneable接口是对某个类起到作用,类和它的所有超类都必须遵守一个想当复杂的、不可实施的,并且基本上没有文档说明的协议。由此得到一种语言之外的机制:

无需要调用构造器就可以创建对象”,红色部分也说明了**行new 一个类是多余的。

3. Object类里面的clone定义。

翻看JDK源码,Object类里面的clone方法定义如下

[java] view plaincopy
  1. protected native Object clone() throws CloneNotSupportedException;
使用C/C++来实现的。

翻了翻相关资料,java clone 克隆 super.clone

是“bitwise(逐位)的复制, 将该对象的内存空间完全复制到新的空间中去”这样实现的。

另外这个方法是protected的,不同的包是不能用的。这就可以解释为什么我们不能显示地调用Object.clone()这个方法。因为Object这个类是放在java,lang这个包里面的,而clone()方法是protected的,是不可见的。如果这样写

[java] view plaincopy
  1. Object o1 = new Object();
  2. Object o2 = o1.clone();
编译器肯定会报错的:

之前我不理解A类中为什么用super.clone()这样子的写法,现在明白了。

4.  如果一个类实现了Cloneable接口,Object的clone方法就会返回该对象的逐域拷贝,否则就会抛出CloneNotSupportedException异常。

来自《effective java》条款11的第二段话。所以要实现对象的clone,必须实现cloneable接口。

相关文章:

持续推进预估时间问题研究,滴滴盖亚计划开放ETA数据集

4月29日消息&#xff0c;为持续推进行程时长预估问题研究&#xff0c;滴滴联合GIS(地理信息系统)领域国际顶会ACM SIGSPATIAL发布ACM SIGSPATIAL GISCUP 2021比赛&#xff0c;鼓励研究者们基于滴滴新开放的行程时长数据集&#xff0c;进一步提升时间预估准确性。 预估到达时间…

3.Java集合-HashSet实现原理及源码分析

一、HashSet概述&#xff1a; HashSet实现Set接口&#xff0c;由哈希表&#xff08;实际上是一个HashMap实例&#xff09;支持&#xff0c;它不保证set的迭代顺序很久不变。此类允许使用null元素 二、HashSet的实现&#xff1a; 对于HashSet而言&#xff0c;它是基于HashMap实现…

一个函数返回多个值

有两种方法&#xff1a;1.使用指针变量声明函数&#xff08;或者使用数组变量&#xff09;2.使用传出参数 第一种方法&#xff1a;函数返回的是一个指针地址&#xff08;数组地址&#xff09;&#xff0c;这个内存地址有多个变量寄存在里面。这个方法我不太会用&#xff0c;传…

4月30日或为上半年“最难打车日”

滴滴出行昨日发布预测&#xff0c;称由于周五通勤晚高峰及假期启程高峰叠加&#xff0c;4月30日下午或将成为今年上半年“最难打车日”&#xff0c;用户将遇到叫车排队甚至打不到车的情况。滴滴呼吁&#xff0c;请提前规划行程&#xff0c;预留充足时间&#xff0c;大家五一快乐…

exchange 2003配置ASSP 反垃圾邮件

Exchange上第三方反垃圾邮件用得比较多的是ORF&#xff0c;它直接运行在虚拟SMTP服务上&#xff0c;配置非常的方便。ASSP&#xff08;https://sourceforge.net/projects/assp/&#xff09; 是一个开源的反垃圾邮件代理&#xff0c;反垃圾效果也非常好&#xff0c;这里不讲如何…

中国人工智能学会通讯——人工智能在各医学亚专科的发展现状及趋势 1.3 人工智能在各医学亚专科的发展态势...

1.3 人工智能在各医学亚专科的发展态势 1. 人工智能在眼科领域的应用 2016年11月&#xff0c;Google的研究者Gulshan博士等人在美国医学协会杂志“Journal of the American Medical Association”上发表的一篇文章&#xff0c;运用deep learning算法&#xff08;卷积神经网络&a…

在ASP.NET中如何用C#.NET实现基于表单的验证

这篇文章引用到了Microsoft .NET类库中的以下名空间&#xff1a; System.Data.SqlClient System.Web.Security &#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff…

PHP学习笔记 第八讲 Mysql.简介和创建新的数据库

八、Mysql.简介和创建新的数据库1、mysql简介与概要mysql是一个小型关系型数据管理系统&#xff0c;开发者为瑞典mysqlab公司现在已经被sun公司收购1.可以处理拥有上千万条记录的大型数据2.支持常见SQL语句规范3.可移植高&#xff0c;安装简单小巧4.良好的运行效率&#xff0c;…

摆脱 FM!这些推荐系统模型真香

‍‍作者 | 梁唐来源 | TechFlow之前我们介绍了推荐当中应用得非常广泛的FM大家族&#xff0c;从FM这个模型衍生出了一系列的模型&#xff0c;从纯FM&#xff0c;到AFM、FFM、DeepFM等等一系列的FM模型&#xff0c;最后的终极版本是xDeepFM。这个模型非常复杂&#xff0c;可以说…

新技术、新思维开创公共安全管理新模式

智慧城市的建设在国内外许多地区正如火如荼的进行中&#xff0c;在为期六天的第十七届中国国际高新技术成果交易会&#xff08;高交会&#xff09;上&#xff0c;智慧城市这一话题再次引发观众及城市建设者们的热议。 尤其是高交会期间召开的“2015亚太智慧城市发展高峰论坛”&…

.Net 中字符串性能

Introduction 你在代码中处理字符串的方法可能会对性能产生令人吃惊的影响。在本文中&#xff0c;我需要考虑两个由于使用字符串而产生的问题&#xff1a;临时字符串变量的使用和字符串连接。 Background 每个项目都有需要你为其考虑编码标准的时候。使用 FxCop 是一个好的开…

Lambda表达式可以被转换为委托类型

void Main() { //向Users类中增加两人; List<Users> usernew List<Users>{ new Users{ID1,Name"Jalen",Age23}, new Users{ID12,Name"Administrator",Age32}, }; //接下来就是利用Linq提供的新的方法来进行相关操作; var userslistuser.Wher…

人工干预如何提高模型性能?看这文就够了!

作者 | Preetam Joshi译者 | 吴家帆出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;有一些行业对误报非常敏感&#xff0c;如金融行业&#xff0c;在对信用卡欺诈检测时&#xff0c;如果检测系统将用户的行为错误地分类为欺诈&#xff0c;这将对该金融机构的声誉产生…

一种无需留坑为页面动态添加View方案

在Activity或Fragment页面动态添加View&#xff0c;有其应用场景&#xff0c;比如配合运营在首页动态插入H5活动页&#xff08;如下图手淘的雪花例示[1]&#xff09;,在页面头部插入通知View等。本文结合ActivityLifecycleCallbacks[2]及DecorView使用&#xff0c;为类似需求提…

边缘加速创新和AI应用,Xilinx推出Kria自适应系统模块产品组合

为了帮助开发者更容易使用FPGA和SoC的功能&#xff0c;赛灵思在开发工具上做了不少的投入&#xff0c;自适应系统模块&#xff08;SOM&#xff09;产品组合就是其中之一。 近日&#xff0c;赛灵思宣布推出Kria™自适应系统模块&#xff08; SOM &#xff09;产品组合&#xff…

windows计算器

using System; using System.Drawing; using System.Windows; using System.Windows.Forms; using System.Collections; using System.ComponentModel; using System.Data; namespace comput{ /// <summary> /// 这是一个计算器的简单实现。 /// </summary&…

哈夫曼树的构造

[转载于网易博客&#xff0c;具体地址不详] 构造哈夫曼树的过程是这样的 一、构成初始集合 对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F{T1,T2,T3,...,Ti,...,Tn}&#xff0c;其中每棵二叉树Ti中只有一个权值为Wi的根结点&#xff0c;它的左右子树均为空…

物联网时代全面降临

从智能建筑到零售&#xff0c;英特尔物联网解决方案可以说是华丽丽地惊艳着大家的大脑和眼球&#xff0c;一切的不可能似乎都在朝着可能的方向努力着。在2015 MWC上&#xff0c;英特尔再次用各种神奇的物联网设备告诉大家&#xff1a;物联网时代已经来临。 “半边天”的力量&am…

Linux C++/Java/Web/OC Socket网络编程

一&#xff0c;Linux C Socket网络编程 1.什么是TCP/IP、UDP&#xff1f; TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;即传输控制协议/网间协议&#xff0c;是一个工业标准的协议集&#xff0c;它是为广域网&#xff08;WANs&#xff09;设…

ASP.NET抓取其他网页代码

在.Net 平台下&#xff0c;创建一个ASP.Net的程序 1、引用两个NAMESPACE using System.Text //因为用了Encoding类 using System.Net //因为用了WebClient 类 2、整个程序用了三个控件 txtUrl //输入你要获取的网页地址 TEXTBOX控件 txtBody //得到你要获取的网…

特斯拉遇上 CPU:程序员的心思你别猜

作者 | 码农的荒岛求生来源 | 码农的荒岛求生图源 | 视觉中国18世纪流水线的诞生带来了制造技术的变革&#xff0c;人类当今拥有琳琅满目物美价廉的商品和流水线技术的发明密不可分&#xff0c;因此当你喝着可乐、吹着空调、坐在特斯拉里拿着智能手机刷这篇文章时需要感谢流水线…

《算法技术手册》一2.4.6 二次方的算法性能

2.4.6 二次方的算法性能 现在考虑一个类似的问题&#xff1a;两个n位的整数相乘。例2-4展示了使用小学课堂上学过的算法实现的乘法运算&#xff0c;其中n位数字的表示方法与之前的加法一样。 例2-4&#xff1a;mult乘法的Java实现 public static void mult (int[] n1, int[] n2…

如何使用 OpenCV 实现图像均衡?

来源 | 小白视觉志头图 | 下载于视觉中国我们已经练习了很多图像处理——操作图像&#xff08;精确地说是图像矩阵&#xff09;。为此&#xff0c;我们探索了图像的均衡方法&#xff0c;以便在一定程度上增强对比度&#xff0c;以使被处理的图像看起来比原始图像更好&#xff0…

《中国人工智能学会通讯》——1.42 理解情感

1.42 理解情感 安德鲁摩尔认为&#xff0c;人工智能能“感受”人类情感是人工智能研究领域最重要、也最先进的一个方向。扬波利斯基认为&#xff0c;计算机能够理解语言的能力最终会向人和计算机“无缝沟通”的方向发展。 越来越精准的图像、声音和面部识别系统能让计算机更好探…

matlab中help所有函数功能的英文翻译

doc funname 在帮助浏览器中打开帮助文档help funname 在命令窗口打开帮助文档helpbrowser 直接打开帮助浏览器lookfor funname 搜索某个关键字相关函数demo 打开视频教程 转http://blog.renren.com/share/239121107/690877048 里面有些不全的&#xff0c;自己用到的已添加…

C# 静态构造函数

&#xff08;1&#xff09;用于对静态字段、只读字段等的初始化。 &#xff08;2&#xff09;添加static关键字&#xff0c;不能添加访问修饰符&#xff0c;因为静态构造函数都是私有的。 &#xff08;3&#xff09;类的静态构造函数在给定应用程序域中…

破解数据流通痛点,华控清交的隐私计算之道

从无序中寻找踪迹&#xff0c;从眼前事探索未来。 正值 IT 黄金十年新开端&#xff0c; CSDN 欲以中立技术社区专业、客观的角度&#xff0c;深度探讨中国前沿 IT 技术演进&#xff0c;现在推出年度重磅企划栏目——「拟合」&#xff0c;通过对话企业高管大咖&#xff0c;跟踪报…

mac系统添加VSCode到右键菜单(转)

转自&#xff1a;https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001470969077294a6455fc9cd1f48b69f82cd05e7fa9b40000 在Mac系统上&#xff0c;Finder选中一个目录&#xff0c;右键菜单并没有“通过Code打开”这个操作。不过我们可以…

在 C# 中通过 P/Invoke 调用Win32 DLL

&#xff0c;.NET Framework 1.0 或 1.1 版类库中存在任何 Windows 所没有的功能限制都不足为怪。毕竟&#xff0c;32 位的 Windows&#xff08;不管何种版本&#xff09;是一个成熟的操作系统&#xff0c;为广大客户服务了十多年。相比之下&#xff0c;.NET Framework 却是一个…

xp/2003开关3389指令

开启3389&#xff1a; echo offtitle 开启3389clsrem 开启3389reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 00000000 /f >nulecho.echo 提示你&#xff1a;3389已经开启 关闭3389&…