Java-克隆

1.假克隆

1.1測試代碼

 /**
     * 假克隆
     * <p>
     * 只複製了對象,沒有複製對象的引用
     */
    private static void testFakeClone() {
        //源對象
        Bean bean = new Bean("張三", new Boss("老大"));

        //這是克隆對象
        Bean clone = bean;
        clone.setName("小明");
        clone.getBoss().setName("頭");

        System.out.println("這是原始數據:");
        System.out.println(JSON.toJSONString(bean));
        System.out.println("這是假克隆:");
        System.out.println(JSON.toJSONString(clone));
    }

1.2.輸出結果:

//這是原始數據:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}
//這是假克隆:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}

1.3.結果分析:

這裏,我們修改了克隆對象的屬性之後,源對象的屬性也同樣變了,關係如圖所示(圖是盜來的,不要糾結於名稱):
這裏寫圖片描述

2.淺克隆

2.1.測試代碼:

/**
     * 淺克隆
     * <p>
     * 既複製了對象,也複製了對象的引用
     * 但是如果引用還存在引用,而更深層的引用如果沒有實現cloneable接口,就還是會指向源對象
     */
    private static void testShallowClone() {
        //源對象
        Bean bean = new Bean("張三", new Boss("老大"));

        //這是克隆對象
        Bean clone = bean.clone();
        clone.setName("小明");
        clone.getBoss().setName("頭");

        System.out.println("這是原始數據:");
        System.out.println(JSON.toJSONString(bean));
        System.out.println("這是淺克隆:");
        System.out.println(JSON.toJSONString(clone));
    }

需要Bean實現Cloneable接口:

/**
     * 被克隆對象
     * <p>
     */
    public static class Bean implements Cloneable {
        private String name;
        private Boss boss;

        public Bean() {
        }

        public Bean(String name, Boss boss) {
            this.name = name;
            this.boss = boss;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Boss getBoss() {
            return boss;
        }

        public void setBoss(Boss boss) {
            this.boss = boss;
        }

        @Override
        protected Bean clone() {
            Bean clone = null;
            try {
                clone = (Bean) super.clone();

            } catch (CloneNotSupportedException e) {
                throw new RuntimeException(e);
            }
            return clone;
        }
    }

2.2.輸出結果:

//這是原始數據:
{
“boss”: {
“name”: “頭”
},
“name”: “張三”
}
//這是淺克隆:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}

2.3.結果分析:

這裏,我們修改了克隆對象的屬性之後,源對象的name屬性沒有變,但是更深的引用boss卻變了,說明此時源對象和克隆對象所引用的boss對象,其實還是同一個,關係如圖所示(圖是盜來的,不要糾結於名稱):
這裏寫圖片描述

深克隆

測試代碼:

/**
     * 深克隆
     * <p>
     * 將對象序列化,再反序列化生成一個新對象即可
     * Serializable、Parcelable、JSON等均可
     */
    private static void testDeepClone() {
        //源對象
        Bean bean = new Bean("張三", new Boss("老大"));

        //這是克隆對象
        String json = JSON.toJSONString(bean);
        Bean clone = JSON.parseObject(json, Bean.class);
        clone.setName("小明");
        clone.getBoss().setName("頭");

        System.out.println("這是原始數據:");
        System.out.println(JSON.toJSONString(bean));
        System.out.println("這是深克隆:");
        System.out.println(JSON.toJSONString(clone));
    }

輸出結果:

//這是原始數據:
{
“boss”: {
“name”: “老大”
},
“name”: “張三”
}
//這是深克隆:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}

結果分析:

這裏寫圖片描述

總結:

  1. clone在平時項目中雖然用的不多,但是,區分深克隆和淺克隆卻可以幫助我們理解java的內存結構
  2. clone的深克隆其實就是序列化和反序列化,這裏有很多種選擇,Serializable、Parcelable、JSON等均可
  3. clone方法不同於new方法,不會執行構造方法

參考目錄:
1. 詳解Java中的clone方法 – 原型模式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章