`
enetor
  • 浏览: 189554 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java clone 详解

阅读更多

转载

 

我们知道,Java是纯面向对象的程序设计语言。Java里,所有的类的顶级父类都是java.lang.Object类,也就是说,如果一个类没有显示申明继承关系,它的父类默认就是java.lang.Object。
                                                                                   
   有一个很简单的方法可以证明这一点,我们写一个Test类,如下:

public class Test {
    public void someMethod() {
        super.clone();
    }
} 
 


里面调用了super.clone(),编译时并不报错。其实clone()方法为java.lang.Object类提供的一个protected型方法。



对象克隆
本文通过介绍java.lang.Object#clone()方法来说明Java语言的对象克隆特性。
java.lang.Object#clone()方法由java.lang.Object加以实现,主要对对象本身加以克隆。
首先我们看看下面的例子:

public class TestClone {
    public static void main(String[] args) {
        MyClone myClone1 = new MyClone("clone1");
       
        MyClone myClone2 = (MyClone)myClone1.clone();
       
        if (myClone2 != null) {
            System.out.println(myClone2.getName());
            System.out.println("myClone2 equals myClone1: " + myClone2.equals(myClone1));
        } else {
            System.out.println("Clone Not Supported");
        }
    }
} 
 

 

class MyClone {
    private String name;
    public MyClone(String name) {
        this.name = name;
    }
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
   
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    } 
 


编译执行TestClone,打印出:

C:\clone>javac *.java
C:\clone>java TestClone
Clone Not Supported
C:\clone>

说明MyClone#clone()方法调用super.clone()时抛出了CloneNotSupportedException异常,不支持克隆。

为什么父类java.lang.Object里提供了clone()方法,却不能调用呢?

原来,Java语言虽然提供了这个方法,但考虑到安全问题, 一方面将clone()访问级别设置为protected型,以限制外部类访问;
另一方面,强制需要提供clone功能的子类实现java.lang.Cloneable接口,在运行期,JVM会检查调用clone()方法的 类,如果该类未实现java.lang.Cloneable接口,则抛出CloneNotSupportedException异常。

java.lang.Cloneable接口是一个空的接口,没有申明任何属性与方法。该接口只是告诉JVM,该接口的实现类需要开放“克隆”功能。

我们再将MyClone类稍作改变,让其实现Cloneable接口:
class MyClone implements Cloneable {
    ...//其余不做改变
}

编译执行TestClone,打印出:

C:\clone>javac *.java
C:\clone>java TestClone
clone1
myClone2 equals myClone1: false
C:\clone>

根据结果,我们可以发现:
1,myClone1.clone()克隆了跟myClone1具有相同属性值的对象
2,但克隆出的对象myClone2跟myClone1不是同一个对象(具有不同的内存空间)

小结:
如果要让一个类A提供克隆功能,该类必须实现java.lang.Cloneable接口,并重载java.lang.Object#clone()方法。

public class A extends Cloneable {
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            //throw (new InternalError(e.getMessage()));
            return null;
        }
    }
} 
 




对象的深层次克隆
  上例说明了怎么样克隆一个具有简单属性(String,int,boolean等)的对象。


但如果一个对象的属性类型是List,Map,或者用户自定义的其他类时,克隆行为是通过怎样的方式进行的?
很多时候,我们希望即使修改了克隆后的对象的属性值,也不会影响到原对象,这种克隆我们称之为对象的深层次克隆。怎么样实现对象的深层次克隆呢?

验证对象的克隆方式
为了验证对象的克隆方式,我们对上面的例子加以改进,如下(为了节省篇幅,我们省略了setter与getter方法):

public class TestClone {
    public static void main(String[] args) {
        //为克隆对象设置值
         MyClone myClone1 = new MyClone("clone1");
         myClone1.setBoolValue(true);
         myClone1.setIntValue(100);
       
        //设置List值
         List <Element>listValue = new ArrayList<Element>();
         listValue.add(new Element("ListElement1"));
         listValue.add(new Element("ListElement2"));
         listValue.add(new Element("ListElement3"));
         myClone1.setListValue(listValue);
       
        //设置Element值
         Element element1 = new Element("element1");
         myClone1.setElement(element1);
       
       
        //克隆
         MyClone myClone2 = (MyClone)myClone1.clone();
       
        if (myClone2 != null) {
           
            //简单属性
             System.out.println("myClone2.name=" + myClone2.getName()
                     + " myClone2.boolValue=" + myClone2.isBoolValue()
                     + " myClone2.intValue=" + myClone2.getIntValue() );
           
            //复合属性(List<Element>与Element)
             List clonedList = myClone2.getListValue();
             Element element2 = myClone2.getElement();
           
             System.out.println("myClone2.listValue.size():" + clonedList.size());
             System.out.println("myClone2.element.equals(myClone1.element):" + element2.equals(element1));
             System.out.println("myClone2.element.name:" + element2.getName());
           
            //下面我们测试一下myClone2.element是否等于myClone1.element
            //以及myClone2.listValue是否等于myClone1.listValue
            //为此,我们修改myClone2.element与myClone2.listValue,如果myClone1的相应值也跟着被修改了,则它们引用的是同一个内存空间的变量,我们认为它们相等
           
             clonedList.add("ListElement4");
           
             System.out.println("myClone1.listValue.size():" + listValue.size());
           
             element2.setName("Element2");
             System.out.println("myClone1.element.name:" + element1.getName());
           
         } else {
             System.out.println("Clone Not Supported");
         }       
       
     }

} 
 



class MyClone implements Cloneable {
    private int intValue;
    private boolean boolValue;
    private String name;
    private List <Element>listValue;
    private Element element;

    public MyClone(String name) {
         this.name = name;
     }

     ...//setter与getter方法(略)
}

class Element implements Cloneable   {
    private String name;
   
    public Element (String name) {
         this.name = name;
     }

     ...//setter与getter方法(略)
} 
 



编译执行TestClone,打印出:

C:\clone>javac *.java
C:\clone>java TestClone
myClone2.name=clone1 myClone2.boolValue=true myClone2.intValue=100
myClone2.listValue.size():3
myClone2.element.equals(myClone1.element):true
myClone2.element.name:element1
myClone1.listValue.size():4
myClone1.element.name:Element2
myClone2 equals myClone1: false
C:\clone>
我们发现,对于对象里的List,Element等复合属性,super.clone()只是简单地赋值,没有采取克隆手段。也就是说,修改被克隆后的对象值,会影响到原对象。

怎么进行深层次的克隆呢?
答案是,我们只能手动在重载的clone()方法里,对属性也分别采用克隆操作。当然条件是,属性类也得支持克隆操作

class MyClone implements Cloneable {
     ...
    public Object clone() {
        try {
             MyClone myClone = (MyClone)super.clone();
            //分别对属性加以克隆操作
             myClone.element = this.element.clone();
           
             myClone.listValue = new ArrayList();
            for (Element ele:this.listValue) {
                 myClone.listValue.add(ele.clone());
             }
                       
            return myClone;
         } catch (CloneNotSupportedException e) {
            return null;
         }
     }
     ...
} 
 


//让Element类也支持克隆操作
class Element implements Cloneable   {
     ...
    public Element clone() {
        try {
            return (Element)super.clone();
         } catch (CloneNotSupportedException e) {
            return null;
         }
     }
} 
 



深层次的克隆操作往往存在效率问题,尤其是需要让List,Map等集合类也支持深层次的克隆操作时。

总结:
本文结合范例,比较深入地介绍了Java语言的克隆属性,以及克隆的实现方法等。同时分析了深层次克隆的概念,实现,以及存在的问题等。 但是有没有更好的方法呢?当然,是有的,串行化来实现。

分享到:
评论

相关推荐

    的最全韩顺平php入门到精通全套笔记.doc )

    【PHP入门】 PHP(Hypertext Preprocessor)是一种广泛使用的开源服务器端脚本语言,尤其适用于Web开发,能够嵌入HTML中。本篇笔记基于韩顺平老师的讲解,全面覆盖了从基础到精通的PHP知识体系。 1. **HTML基础** HTML,即超文本标记语言,用于创建网页内容。它包括各种标签来定义网页结构,如`<html>`、`<head>`、`<body>`等。HTML与CSS结合使用,可以实现页面样式控制。HTML5作为最新版本,引入了更多增强功能,如离线存储、拖放功能和媒体元素等。运行HTML有两种方式:本地运行(直接通过浏览器打开文件)和远程访问(通过HTTP协议在服务器上运行)。 2. **动态网页技术** 动态网页能够根据用户输入或服务器状态变化实时更新内容。PHP作为动态网页开发的重要技术之一,具有跨平台、安全性高、效率好、成本低、易于学习和丰富的开源社区支持等优点。PHP可以连接多种数据库,如MySQL,并在PHP4、PHP5和PHP6(及后续版本)中逐。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    花生好坏缺陷识别数据集,7262张图片,支持yolov7格式的标注,识别准确率在95.7%

    花生好坏缺陷识别数据集,7262张图片,支持yolov7格式的标注,识别准确率在95.7% 两种标签: Good,Bad 花生好坏缺陷识别数据集,7262张图片,支持yolo,coco json,pasical voc xml格式的标注,识别准确率在95.7% 详情查看地址:https://backend.blog.csdn.net/article/details/144983881

    总务科(基建办)2024年工作总结.doc

    总务科(基建办)2024年工作总结.doc

    基于springboot+vue的相亲网站(Java毕业设计,附源码,部署教程).zip

    该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven

    广东省高清卫星地图全图

    广东省高清卫星地图全图

    智能聊天机器人在电商客服领域的应用研究与开发毕业设计报告

    本文聚焦智能聊天机器人于电商客服领域的应用,开篇点明研究背景,剖析电商发展促使客服需求暴增,传统客服乏力,智能机器人应运而生。接着详述电商客服发展脉络、现存痛点,如高峰拥堵、知识滞后、服务同质化等。核心技术涵盖自然语言处理、机器学习、知识图谱,系统采用微服务架构,各模块分工协作。开发流程包括精细调研、多元数据采集、模型选型调优等。创新应用体现于售前精准导购、沉浸式营销,售中订单跟踪、答疑,售后问题处理与回访。经量化指标与用户调研评估成效显著,虽有挑战,但未来借助新技术有望重塑电商服务生态,助力企业与消费者双赢。

    基于springboot+vue的人口老龄化社区服务与管理平台(Java毕业设计,附源码,部署教程).zip

    该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven

    eap2025010741566905-1-1.pdf

    eap2025010741566905-1-1.pdf

    双馈风机MATLAB simulink模型 多个模型打包发送

    双馈风机MATLAB simulink模型 多个模型打包发送

    小熊汉字笔顺学习软件 v2.0

    给小孩找的,看着还不错,分享出来~

    基于springboot+vue的美容院管理系统(Java毕业设计,附源码,部署教程).zip

    该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven

    bcolz-1.2.1-cp38-cp38-win-amd64.whl.rar

    bcolz-1.2.1-cp38-cp38-win-amd64.whl.rar

    自动驾驶技术中域控制单元(DCU)的核心作用与发展前景

    内容概要:本文详尽阐述了自动驾驶技术中的域控制单元(DCU)及其重要性。首先介绍了ADAS(高级驾驶辅助系统)和AD(自动驾驶)的区别和发展现状。接着讨论了域控制单元作为高级ECU,在自动驾驶系统中扮演的重要角色,包括高性能计算、高效的数据处理能力和与其他子系统的紧密配合。文中详细解释了DCU的构成元素——收发器、SoC、MCU和电源管理等模块的工作原理和技术细节,同时也探讨了市场趋势和技术发展趋势,如高集成度、智能化、低功耗等方面。最后展望了DCU在未来域集中式EE架构下的广阔应用前景。 适用人群:从事汽车工程、自动驾驶技术和嵌入式软件开发的专业技术人员,以及对此领域感兴趣的科研工作者。 使用场景及目标:①帮助开发者深入了解自动驾驶系统组成尤其是DCU的设计理念和技术特征;②指导相关领域的研究者把握当前行业发展动态和技术前沿。 其他说明:本文不仅深入浅出地讲解了专业知识,而且引用了一些作者个人感悟的文字,增加了可读性和启发性。

    Java与Python编程语言特性、应用场景及其学习选择

    内容概要:文章主要介绍了Java和Python这两种流行的编程语言之间的区别和联系。首先详细讲述了Java的基本特性,包括跨平台性、面向对象编程、类型安全、自动化内存管理和多线程支持等特点,并概述了其在企业级开发中的广泛应用。接着深入探讨了Python的特点,指出它的简明语法、灵活性以及丰富的生态体系,特别提到了其在数据分析、人工智能等前沿领域的优势。文中还比较了两者的应用场景和技术实现方式的不同之处。最后为初学者提出了基于个人职业发展目标来选择编程语言的建议。 适合人群:对编程有兴趣的学生、编程新手以及想要转换编程方向的技术人员。 使用场景及目标:有助于读者理解两种编程语言各自的优劣,便于在实际工作中或者个人兴趣发展中做出明智的选择。 其他说明:通过对比讲解,不仅展示了两种编程语言的共同点,还强调了它们各自独特的优势所在。这有助于加深读者对其本质特征的认识,从而更好地应对不同类型的编程任务和挑战。

    Java 飞机订票系统实训报告

    Java 飞机订票系统实训报告,有数据库

    easy-interceptor修改请求头和响应头.zip

    easy-interceptor修改请求头和响应头.zip

    Python身份证识别系统源码(精准度非常高).zip

    Python身份证识别系统源码(精准度非常高).zip,个人大三大作业设计项目、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 Python身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系

    【电磁】基于matlab微带线中的电势和场分布【含Matlab源码 10949期】.zip

    Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作

    一个利用深度学习模型(LSTM 网络)对电商用户咨询文本进行意图分类的python源码

    功能:利用深度学习模型(LSTM 网络)对电商用户咨询文本进行意图分类,相比简单规则匹配,能处理更复杂、语义模糊的文本,精准识别用户需求。 技术要点:使用 TensorFlow 构建 LSTM 模型,包括文本预处理将文本数字化,Embedding 层将数字映射为向量,LSTM 层捕捉序列特征,Dense 层输出分类结果,通过训练优化模型参数,实现准确意图识别。

    国产银河麒麟V10和统信系统(linux)没有root用户的解决办法

    国产银河麒麟V10和统信系统(linux)没有root用户的解决办法。如何在没有root用户的情况下,开通和启用root用户

Global site tag (gtag.js) - Google Analytics