1. 程式人生 > >java淺拷貝和深拷貝(基礎也是很重要的)

java淺拷貝和深拷貝(基礎也是很重要的)

inf n) vat 實現 技術 變量 hub -h 接口

對象的copy你興許只是懵懂,或者是並沒在意,來了解下吧。

對於的github基礎代碼https://github.com/chywx/JavaSE

最近學習c++,跟java很是相像,在慕課網學習c++也算是重溫習了下java基礎

明白了當初講師一直強調java傳遞的話只有值傳遞,不存在引用傳遞,為什麽一直要重復這,既然只有值傳遞,為啥還強調不是引用傳遞

毛病啊這是

學了c++才知道,原來c++有值傳遞,引用傳遞的說法,但是java只是值傳遞

最簡單的理解就是對於方法調用

比如 f(int a,int b) 這是值傳遞,傳遞過來的值不會被修改。

再如 f(int &a,int &b)這是引用傳遞,傳遞過來的值會被修改

步入正軌,說一說java的淺拷貝(Shallow Copy)、深拷貝(Deep Copy)。

淺拷貝(Shallow Copy):①對於數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值復制一份給新的對象。因為是兩份不同的數據,所以對其中一個對象的該成員變量值進行修改,不會影響另一個對象拷貝得到的數據。②對於數據類型是引用數據類型的成員變量,比如說成員變量是某個數組、某個類的對象等,那麽淺拷貝會進行引用傳遞,也就是只是將該成員變量的引用值(內存地址)復制一份給新的對象。因為實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響

到另一個對象的該成員變量值。

通過示例來了解下,技術分享圖片

一:

  使用構造函數實現copy

public class Person {
    public static void main(String[] args) {
        Son s = new Son(10);
        Person p1 = new Person("大海", s);
        Person p2 = new Person(p1);
        p1.setSonName("小海");
        p1.getSon().setAge(12);
        System.out.println(
"p1:" + p1);// p1:Person [sonName=小海, son=Son [age=10]] System.out.println("p2:" + p2);// p2:Person [sonName=大海, son=Son [age=10]] } private String sonName; private Son son; // 自定義拷貝函數 public Person(Person person) { this.sonName = person.sonName; this.son = person.son; } public Person(String sonName, Son son) { super(); this.sonName = sonName; this.son = son; } public String getSonName() { return sonName; } public void setSonName(String sonName) { this.sonName = sonName; } public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } @Override public String toString() { return "Person [sonName=" + sonName + ", son=" + son + "]"; } } class Son { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Son(int age) { super(); this.age = age; } @Override public String toString() { return "Son [age=" + age + "]"; } }

結果

p1:Person [sonName=小海, son=Son [age=12]]
p2:Person [sonName=大海, son=Son [age=12]]

對於上面的實例,該person對象有兩個成員,一個基本類型,一個引用類型,結果是拷貝出來的對象,基本類型的那個成員真正的實現了copy。

二:

  使用自帶的clone方法,需要實現cloneable接口,不然會

Exception in thread "main" java.lang.CloneNotSupportedException:

技術分享圖片

技術分享圖片

public class Person2 implements Cloneable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Son2 son1 = new Son2(10);

        Person2 person1 = new Person2("大海", son1);
        Person2 person2 = (Person2) person1.clone();
        person2.setSon2Name("小海");
        person2.getSon2().setAge(12);
        System.out.println(person1);
        System.out.println(person2);
    }

    public Person2(String son2Name, Son2 son2) {
        super();
        this.son2Name = son2Name;
        this.son2 = son2;
    }

    private String son2Name;
    private Son2 son2;

    public String getSon2Name() {
        return son2Name;
    }

    public void setSon2Name(String son2Name) {
        this.son2Name = son2Name;
    }

    public Son2 getSon2() {
        return son2;
    }

    public void setSon2(Son2 son2) {
        this.son2 = son2;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Person2 [son2Name=" + son2Name + ", son2=" + son2 + "]";
    }

}

class Son2 {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Son2 [age=" + age + "]";
    }

    public Son2(int age) {
        super();
        this.age = age;
    }

}

結果:

Person2 [son2Name=大海, son2=Son2 [age=12]]
Person2 [son2Name=小海, son2=Son2 [age=12]]

使用自帶的copy實現淺拷貝

---------------------------------------------------------------------------------------------------

深拷貝

  相對於淺拷貝而言,對於引用類型的修改,並不會影響到對應的copy對象的值。每一層的每個對象都進行淺拷貝=深拷貝。

一:

  還是使用clone方法,只不過得手動重寫一下。

技術分享圖片

上代碼

public class Person3 implements Cloneable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Son3 son1 = new Son3(10);
        Person3 person1 = new Person3("大海", son1);
        Person3 person2 = (Person3) person1.clone();
        person2.setSon2Name("小海");
        person2.getSon3().setAge(12);//修改對應的引用對象的值。
        System.out.println(person1);
        System.out.println(person2);
    }

    public Person3(String son2Name, Son3 son3) {
        super();
        this.son2Name = son2Name;
        this.son3 = son3;
    }

    private String son2Name;
    private Son3 son3;

    public String getSon2Name() {
        return son2Name;
    }

    public void setSon2Name(String son2Name) {
        this.son2Name = son2Name;
    }

    public Son3 getSon3() {
        return son3;
    }

    public void setSon3(Son3 son3) {
        this.son3 = son3;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person3 clone = (Person3) super.clone();
        clone.setSon3((Son3) clone.getSon3().clone());
        return clone;
    }

    @Override
    public String toString() {
        return "Person3 [son2Name=" + son2Name + ", son3=" + son3 + "]";
    }

}

class Son3 implements Cloneable {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Son2 [age=" + age + "]";
    }

    public Son3(int age) {
        super();
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

結果:

Person3 [son2Name=大海, son3=Son2 [age=10]]

Person3 [son2Name=小海, son3=Son2 [age=12]]

方法二:

  顯然對於多個對象的話,顯然就很吃力。可以使用另一種方式,

  將對象序列化為字節序列後,默認會將該對象的整個對象圖進行序列化,再通過反序列即可完美地實現深拷貝。

技術分享圖片

public class Person4 implements Serializable {
    public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
        Son4 son = new Son4(10);
        Person4 person1 = new Person4("大海", son);
        //通過序列化方法實現深拷貝
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(person1);
        oos.flush();
        ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        Person4 person2=(Person4)ois.readObject();
        person1.setSon4Name("小海");
        person1.getSon4().setAge(12);
        System.out.println(person1.toString());
        System.out.println(person2.toString());
    }

    public Person4(String son4Name, Son4 son4) {
        super();
        this.son4Name = son4Name;
        this.son4 = son4;
    }

    private String son4Name;
    private Son4 son4;

    public String getSon4Name() {
        return son4Name;
    }

    public void setSon4Name(String son4Name) {
        this.son4Name = son4Name;
    }

    public Son4 getSon4() {
        return son4;
    }

    public void setSon4(Son4 son4) {
        this.son4 = son4;
    }

    @Override
    public String toString() {
        return "Person4 [son4Name=" + son4Name + ", son4=" + son4 + "]";
    }
}

class Son4 implements Serializable {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Son2 [age=" + age + "]";
    }

    public Son4(int age) {
        super();
        this.age = age;
    }

}

這是實現序列化接口方案,nice.

perfect!!!到位

java淺拷貝和深拷貝(基礎也是很重要的)