Java clone() 方法克隆對象——深拷貝與淺拷貝


基本數據類型引用數據類型特點

1、基本數據類型的特點:直接存儲在棧(stack)中的數據

2、引用數據類型的特點:存儲的是該對象在棧中引用,真實的數據存放在堆內存里

引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址后從堆中獲得實體。

深拷貝與淺拷貝特點

淺拷貝只復制指向某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內存。但深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。

當把一個對象賦值給一個新的變量時,賦的其實是該對象的在棧中的地址,而不是堆中的數據。也就是兩個對象指向的是同一個存儲空間,無論哪個對象發生改變,其實都是改變的存儲空間的內容,因此,兩個對象是聯動的。

淺拷貝是按位拷貝對象,它會創建一個新對象,這個對象有着原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內存地址(引用類型),拷貝的就是內存地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象。即默認拷貝構造函數只是對對象進行淺拷貝復制(逐個成員依次拷貝),即只復制對象空間而不復制資源。

Java clone方法深拷貝與淺拷貝

clone淺拷貝

由CloneDemo類可以看出,沒有重寫clone方法,對象中的引用數據類型只是復制了該引用數據類型的引用,並沒有在內存空間中開辟空間復制該引用數據類型,即對該引用數據類型進行了淺拷貝而不是深拷貝。

package JDKSource.lang;

public class CloneDemo implements Cloneable {
    private int num;
    private String name;
    private Helper helper;

    public CloneDemo() {
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

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

    public Helper getHelper() {
        return helper;
    }

    @Override
    public String toString() {
        return "CloneDemo{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", helper=" + helper +
                '}';
    }

    public void setHelper(Helper helper) {
        this.helper = helper;
    }

    public static class Helper {
        public int num;

        public Helper(int num) {
            this.num = num;
        }

        public int getNum() {
            return num;
        }

        public void setNum(int num) {
            this.num = num;
        }

        @Override
        public String toString() {
            return "Helper{" +
                    "num=" + num +
                    '}';
        }
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneDemo d1 = new CloneDemo();
        d1.setName("Jack");
        d1.setNum(10);
        d1.setHelper(new Helper(100));
        CloneDemo d2 = (CloneDemo) d1.clone();
        System.out.println(d1.name == d2.name);
        System.out.println(d1.num == d2.num);
        System.out.println(d1.helper == d2.helper);
        d2.setNum(11);
        d2.setName("json");
        d2.getHelper().setNum(101);
        System.out.println(d1.name);
        System.out.println(d1.num);
        System.out.println(d1.helper.toString());
 		System.out.println(d2.name);
        System.out.println(d2.num);
        System.out.println(d2.helper.toString());
/*      Output:
        true
        true
        true
        Jack
        10
        Helper{num=101}
        json
        11
        Helper{num=101}*/
    }
}

clone深拷貝

對Helper類和CloneDemo都重寫clone方法:

CloneDemo重寫clone方法:

@Override
protected CloneDemo clone() throws CloneNotSupportedException {
    CloneDemo clone = (CloneDemo1) super.clone();
    clone.helper = helper.clone();
    return clone;
}

Helper重寫clone方法:

@Override
protected Helper clone() throws CloneNotSupportedException {
    Helper helper = null;
    Helper clone = (Helper) super.clone();
    return clone;
}

輸出結果:

結果顯示,對Helper類和CloneDemo都重寫clone方法后,實現了對引用數據類型Helper的深拷貝。

/*      Output:
        true
        true
        false
        Jack
        10
        Helper{num=100}
        json
        11
        Helper{num=101}*/

完整代碼:

package JDKSource.lang;


public class CloneDemo1 implements Cloneable {
    private int num;
    private String name;
    private Helper helper;

    public CloneDemo1() {
    }


    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

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

    public Helper getHelper() {
        return helper;
    }

    @Override
    protected CloneDemo1 clone() throws CloneNotSupportedException {
        CloneDemo1 clone = (CloneDemo1) super.clone();
        clone.helper = helper.clone();
        return clone;
    }

    @Override
    public String toString() {
        return "CloneDemo{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", helper=" + helper +
                '}';
    }

    public void setHelper(Helper helper) {
        this.helper = helper;
    }

    public static class Helper implements Cloneable {
        public int num;

        public Helper(int num) {
            this.num = num;
        }

        public int getNum() {
            return num;
        }

        public void setNum(int num) {
            this.num = num;
        }

        @Override
        public String toString() {
            return "Helper{" +
                    "num=" + num +
                    '}';
        }

        @Override
        protected Helper clone() throws CloneNotSupportedException {
            Helper helper = null;
            Helper clone = (Helper) super.clone();
            return clone;
        }
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        CloneDemo1 d1 = new CloneDemo1();
        d1.setName("Jack");
        d1.setNum(10);
        d1.setHelper(new Helper(100));
        CloneDemo1 d2 = (CloneDemo1) d1.clone();
        System.out.println(d1.name == d2.name);
        System.out.println(d1.num == d2.num);
        System.out.println(d1.helper == d2.helper);
        d2.setNum(11);
        d2.setName("json");
        d2.getHelper().setNum(101);
        System.out.println(d1.name);
        System.out.println(d1.num);
        System.out.println(d1.helper.toString());
        System.out.println(d2.name);
        System.out.println(d2.num);
        System.out.println(d2.helper.toString());
/*      Output:
        true
        true
        false
        Jack
        10
        Helper{num=100}
        json
        11
        Helper{num=101}*/
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM