首頁 > Java > java教程 > 主體

Java Cloneable介面的深拷貝與淺拷貝方法

PHPz
發布: 2023-04-28 08:49:13
轉載
1051 人瀏覽過

    Cloneable介面原始碼

    Cloneable介面:

    實作此介面的類別——可被推斷java.lang.Object的clone()方法可以被合法地呼叫-以實作類別實例:屬性到屬性的拷貝。

    如果一個類別未實作Cloneable介面,那麼呼叫clone()方法時,會拋出CloneNotSupportedException異常。

    通常,實作了Cloneable介面的子類別,應當以public存取權重寫clone()方法(儘管java.Object類別中的clone方法是protected類型的)

    應當認識到:Cloneable介面沒有包含clone()方法,因此,如果僅僅是implements了Cloneable介面,那麼也是無法正常複製物件的

    [原因:即使是反射性地呼叫了克隆方法,也不能保證它一定會成功]——個人理解就是:是否重寫Clone()方法、或「淺拷貝與深拷貝」問題的存在所導致的。

    class Pet implements Cloneable{
        //properties
        private String name;
        public void setName(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public Pet() {
        }
        public Pet(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Pet{" +
                    "name='" + name + '\'' +
                    '}';
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pet pet = (Pet) o;
            return Objects.equals(name, pet.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    //    @Override
    //    public Pet clone() {
    //        try {
    //            return (Pet)super.clone();
    //        } catch (CloneNotSupportedException e) {
    //            e.printStackTrace();
    //        }
    //        return null;
    //    }
    }
    登入後複製
    登入後複製
    登入後複製

    淺拷貝案例

    Pet類別定義

    #注意到:Pet類別實作了Cloneable接口,但是沒有重寫Clone()方法(顯然:此時Pet類別不具備物件克隆的能力)。

    class Pet implements Cloneable{
        //properties
        private String name;
        public void setName(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public Pet() {
        }
        public Pet(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Pet{" +
                    "name='" + name + '\'' +
                    '}';
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pet pet = (Pet) o;
            return Objects.equals(name, pet.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    //    @Override
    //    public Pet clone() {
    //        try {
    //            return (Pet)super.clone();
    //        } catch (CloneNotSupportedException e) {
    //            e.printStackTrace();
    //        }
    //        return null;
    //    }
    }
    登入後複製
    登入後複製
    登入後複製

    Person類別定義

    注意到:Person類別實作了Cloneable接口,也重寫Clone()方法。那麼,是否Person類別就具備了物件克隆的能力呢? (由於淺拷貝問題的存在,認為這種物件克隆能力是不完整的、有缺陷的)。

    class Pet implements Cloneable{
        //properties
        private String name;
        public void setName(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public Pet() {
        }
        public Pet(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Pet{" +
                    "name='" + name + '\'' +
                    '}';
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pet pet = (Pet) o;
            return Objects.equals(name, pet.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    //    @Override
    //    public Pet clone() {
    //        try {
    //            return (Pet)super.clone();
    //        } catch (CloneNotSupportedException e) {
    //            e.printStackTrace();
    //        }
    //        return null;
    //    }
    }
    登入後複製
    登入後複製
    登入後複製

    淺拷貝問題-程式碼測試

    為什麼說:此時Person類別的物件克隆能力是不完整的、有缺陷的?因為此時,在透過Person物件呼叫clone()方法,複製物件時,其成員屬性pet(Pet類別的物件)值的克隆,僅僅是對堆區記憶體位址的簡單拷貝。

    即:說白了,Person對象和克隆出來的對象,其pet屬性值共享同一塊堆區記憶體。 ——問題顯而易見:當對複製出來的物件的pet屬性進行set操作時,顯然會影響到原始Person物件的pet屬性值。

    程式碼示範如下:

      //methods
        public static void main(String[] args) throws CloneNotSupportedException {
            testPerson();
        }
        public static void testPerson() throws CloneNotSupportedException {
            Person p=new Person("张三",14,new Pet("小黑"));
            System.out.println(p);
            Person clone = (Person)p.clone();
            System.out.println(clone);
            System.out.println(p.equals(clone));
            System.out.println(p.getPet()==clone.getPet());
            System.out.println("************");
            clone.setAge(15);
            System.out.println(p);
            System.out.println(clone);
            System.out.println(p.equals(clone));
            System.out.println("************");
            clone.getPet().setName("小黄");
            System.out.println(p);
            System.out.println(clone);
            System.out.println(p.equals(clone));
            System.out.println(p.getPet()==clone.getPet());
        }
    登入後複製

    Java Cloneable介面的深拷貝與淺拷貝方法

    #深拷貝案例

    那麼,要如何實現深拷貝呢?關鍵就在上述案例中,被註解的幾行程式碼中。

    Pet類別重寫clone()方法

    Java Cloneable介面的深拷貝與淺拷貝方法

    #Person的clone()方法中呼叫Pet的clone方法

    Java Cloneable介面的深拷貝與淺拷貝方法

    淺拷貝問題解決-深拷貝程式碼測試

    測試程式碼不變,再執行一次:

    Java Cloneable介面的深拷貝與淺拷貝方法

    以上是Java Cloneable介面的深拷貝與淺拷貝方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    相關標籤:
    來源:yisu.com
    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
    熱門教學
    更多>
    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板
    關於我們 免責聲明 Sitemap
    PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!