轻识Logo
目录

    深克隆和浅克隆有什么区别?它的实现方式有哪些?

    什么是浅克隆和深克隆

    • 浅克隆(Shadow Clone)是把原型对象中成员变量为值类型的属性都复制给克隆对象,把原型对象中成员变量为引用类型的引用地址也复制给克隆对象,也就是原型对象中如果有成员变量为引用对象,则此引用对象的地址是共享给原型对象和克隆对象的。

    • 简单来说就是浅克隆只会复制原型对象,但不会复制它所引用的对象

    • 深克隆(Deep Clone)是将原型对象中的所有类型,无论是值类型还是引用类型,都复制一份给克隆对象,也就是说深克隆会把原型对象和原型对象所引用的对象,都复制一份给克隆对象,如下图所示:


    如何实现克隆

    在 Java 语言中要实现克隆则需要实现 Cloneable 接口,并重写 Object 类中的 clone() 方法,实现代码如下:

    public class CloneExample {

        public static void main(String[] args) throws CloneNotSupportedException {

            // 创建被赋值对象

            People p1 = new People();

            p1.setId(1);

            p1.setName("Java");

            // 克隆 p1 对象

            People p2 = (People) p1.clone();

            // 打印名称

            System.out.println("p2:" + p2.getName());

        }

        static class People implements Cloneable {

            // 属性

            private Integer id;

            private String name;

            /**

             * 重写 clone 方法

             * @throws CloneNotSupportedException

             */


            @Override

            protected Object clone() throws CloneNotSupportedException {

                return super.clone();

            }

            public Integer getId() {

                return id;

            }

            public void setId(Integer id) {

                this.id = id;

            }

            public String getName() {

                return name;

            }

            public void setName(String name) {

                this.name = name;

            }

        }

    }

    执行结果为:

    p2:Java

    在 java.lang.Object 中对 clone() 方法的约定有哪些?

    • 对于所有对象来说,x.clone() !=x 应当返回 true,因为克隆对象与原对象不是同一个对象;

    • 对于所有对象来说,x.clone().getClass() == x.getClass() 应当返回 true,因为克隆对象与原对象的类型是一样的;

    • 对于所有对象来说,x.clone().equals(x) 应当返回 true,因为使用 equals 比较时,它们的值都是相同的。

    Arrays.copyOf() 是深克隆还是浅克隆?

    • 如果是数组类型,我们可以直接使用 Arrays.copyOf() 来实现克隆,实现代码如下:

    People[] o1 = {new People(1"Java")};

    People[] o2 = Arrays.copyOf(o1, o1.length);

    // 修改原型对象的第一个元素的值

    o1[0].setName("Jdk");

    System.out.println("o1:" + o1[0].getName());

    System.out.println("o2:" + o2[0].getName());

    执行结果:

    o1:Jdk

    o2:Jdk
    • 从结果可以看出,我们在修改克隆对象的第一个元素之后,原型对象的第一个元素也跟着被修改了,这说明 Arrays.copyOf() 其实是一个浅克隆。

    • 因为数组比较特殊数组本身就是引用类型,因此在使用 Arrays.copyOf() 其实只是把引用地址复制了一份给克隆对象,如果修改了它的引用对象,那么指向它的(引用地址)所有对象都会发生改变,因此看到的结果是,修改了克隆对象的第一个元素,原型对象也跟着被修改了。

    深克隆的实现方式有几种?

    • 所有对象都实现克隆方法;

    • 通过构造方法实现深克隆;

    • 使用 JDK 自带的字节流实现深克隆;

    • 使用第三方工具实现深克隆,比如 Apache Commons Lang;

    • 使用 JSON 工具类实现深克隆,比如 Gson、FastJSON 等。

    具体代码实现方式可以查看:
    https://shimo.im/docs/L9kBMnZ56GTnDRqK/ 《深克隆和浅克隆有什么区别?它的实现方式有哪些?》,可复制链接后用石墨文档 App 或小程序打开

    Java 中的克隆为什么要设计成,既要实现空接口 Cloneable,还要重写 Object 的 clone() 方法?

    • Java 中实现克隆需要两个主要的步骤,一是 实现 Cloneable 空接口,二是重写 Object 的 clone() 方法再调用父类的克隆方法 (super.clone())

    从源码中可以看出 Cloneable 接口诞生的比较早,JDK 1.0 就已经存在了,因此从那个时候就已经有克隆方法了,那我们怎么来标识一个类级别对象拥有克隆方法呢?克隆虽然重要,但我们不能给每个类都默认加上克隆,这显然是不合适的,那我们能使用的手段就只有这几个了:

    • 在类上新增标识,此标识用于声明某个类拥有克隆的功能,像 final 关键字一样;

    • 使用 Java 中的注解;

    • 实现某个接口;

    • 继承某个类。

    第一个,为了一个重要但不常用的克隆功能, 单独新增一个类标识,这显然不合适;第二个,因为克隆功能出现的比较早,那时候还没有注解功能,因此也不能使用;第三点基本满足我们的需求,第四点和第一点比较类似,为了一个克隆功能需要牺牲一个基类,并且 Java 只能单继承,因此这个方案也不合适。采用排除法,无疑使用实现接口的方式是那时最合理的方案了,而且在 Java 语言中一个类可以实现多个接口。

    • 那为什么要在 Object 中添加一个 clone() 方法呢?

    因为 clone() 方法语义的特殊性,因此最好能有 JVM 的直接支持,既然要 JVM 直接支持,就要找一个 API 来把这个方法暴露出来才行,最直接的做法就是把它放入到一个所有类的基类 Object 中,这样所有类就可以很方便地调用到了。


    浏览 43
    点赞
    评论
    收藏
    分享

    手机扫一扫分享

    举报
    人机交互的方式有哪些
    深度学习视觉
    0
    Java 浅拷贝和深拷贝的理解和实现方式
    Java有货
    0
    InstikiWiki 克隆
    Instiki是一个Wiki克隆,因此非常漂亮且易于设置,您会怀疑它是否真的是Wiki。在Rails上运行,并专注于可移植性和稳定性。支持文件上传,PDF导出,RSS,多个用户和密码保护。由于Inst
    InstikiWiki 克隆
    0
    InstikiWiki 克隆
    Instiki是一个Wiki克隆,因此非常漂亮且易于设置,您会怀疑它是否真的是Wiki。在Rails
    InstikiWiki 克隆
    0
    CRM和SCRM有什么区别?
    看到这个问题正好我最近整理了一篇关于SCRM的文章,这里也跟大家分享下我对SCRM的理解和认识。这些理解来源自我日常的工作和总结,希望能让大家对SCRM有详细的了解。 从2011年开始,时趣在市场上首创了一个新的概念叫SCRM:Social Customer Relationship Management。然后我们就一直面对着各种问题:SCRM和CRM有什么关系?你们的SCRM是用来管销售的么?SCRM的市场是不是一个很小的Niche Market?思考和实践了4年多,今天我来认真写写,到底SCRM是什么? 营销CRM就营销CRM,SCRM又是怎么回事? 中国是个神奇的国度,我们的后发优势使得我们不停的在弯道上超车,这次我们超
    张锐
    0
    while(1) 和 for(;;)有什么区别?
    Stephen
    0
    OracleJDK和OpenJDK有什么区别?
    Kirito的技术分享
    0
    while(1) 和 for(;;) 有什么区别?
    这是「进击的Coder」的第 551 篇技术分享作者:strongerHuang来源:嵌入式专栏“ 阅读本文大概需要 5 分钟。 ”有读者问题了类似这样的问题:while(1) 和 for(;;) 它们不都是无限循环吗,作用应该一样啊,它们到底有什...
    FightingCoder
    0
    while(1) 和 for(;;)有什么区别?
    ACM比赛整理
    0
    点赞
    评论
    收藏
    分享

    手机扫一扫分享

    举报

    深圳SEO优化公司坪山网站开发横岗建网站木棉湾企业网站改版松岗设计公司网站南联模板网站建设民治百搜标王横岗设计网站广州百度竞价大浪网站设计模板南联seo排名福永网站定制大鹏SEO按天计费平湖网站优化坑梓建设网站坑梓SEO按效果付费盐田如何制作网站大芬网络营销爱联seo网站优化平湖外贸网站制作宝安外贸网站制作平湖seo排名爱联网络广告推广福永百姓网标王推广石岩网站搭建坑梓模板网站建设坂田SEO按天计费南山网络推广大芬外贸网站建设广州英文网站建设罗湖百搜词包歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

    深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化