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


對象的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!!!到位

 記錄下聽得歌曲。

    絕世
            (張克帆)
世間種種的誘惑
不驚不擾我清夢
山高路遠不絕我
追蹤你絕美的笑容
登高一呼時才懂
始終在為你心痛
俯首對花影搖動
都是東風在捉弄
世間種種的迷惑
都是因你而猜錯
水光月光又交融
描述這朗朗的夜空
生死到頭的相從
似狂花落葉般從容
當一切泯滅如夢
就在遠山被絕世塵封            

 

 

 

 


免責聲明!

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



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