您好,登錄后才能下訂單哦!
這篇文章給大家介紹Java中淺拷貝和深拷貝該怎么理解,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
淺拷貝和深拷貝涉及到了Object類中的clone()方法
淺拷貝的實現需要類重寫clone()方法
淺拷貝會創建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝
如果屬性是基本類型,拷貝的就是基本類型的值;
如果屬性是內存地址(引用類型),拷貝的就是內存地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象,導致兩個對象的引用不等。
實現淺拷貝很簡單只需要將類實現Cloneable接口然后重寫clone方法即可
class Person implements Cloneable { String name; int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } /** * 重寫clone()方法 * * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
測試淺拷貝特性
public void testClone() throws CloneNotSupportedException { Person person1 = new Person(); person1.setName("ccy"); person1.setAge(20); Person person2 = (Person) person1.clone(); //查看淺拷貝效果 System.out.println(person1); System.out.println(person2); System.out.println(person1.getName() == person2.getName()); //驗證clone()的特性 System.out.println(person1.clone() != person1); System.out.println(person1.clone().getClass() == person1.getClass()); //如果是基本類型淺拷貝直接賦值值,如果是引用類型淺拷貝指向其內存地址即共享內存地址 //改變person1的引用類型String屬性的值,引用發生改變 person1.setName("zfs"); System.out.println(person2.getName()); }
對于上述的問題雖然拷貝的兩個對象不同,但其內部的一些引用還是相同的,怎么樣絕對的拷貝這個對象,使這個對象完全獨立于原對象呢?就使用我們的深拷貝了。深拷貝:在對引用數據類型進行拷貝的時候,創建了一個新的對象,并且復制其內的成員變量。
在具體實現深拷貝上,這里提供兩個方式,重寫clone()方法和序列法。
重寫clone()方法
如果使用重寫clone()方法實現深拷貝,那么要將類中所有自定義引用變量的類也去實現Cloneable接口實現clone()方法。對于字符類可以創建一個新的字符串實現拷貝。但是對于自定義類需要實現cloneable重寫clone,這樣做就太麻煩了所以我們使用序列化
序列化
序列化后將二進制字節流內容寫到一個媒介(文本或字節數組),然后是從這個媒介讀取數據,原對象寫入這個媒介后拷貝給clone對象,原對象的修改不會影響clone對象,因為clone對象是從這個媒介讀取。
熟悉對象緩存的知道我們經常將Java對象緩存到Redis中,然后還可能從Redis中讀取生成Java對象,這就用到序列化和反序列化。一般可以將Java對象存儲為字節流或者json串然后反序列化成Java對象。因為序列化會儲存對象的屬性但是不會也無法存儲對象在內存中地址相關信息。所以在反序列化成Java對象時候會重新創建所有的引用對象。
在具體實現上,自定義的類需要實現Serializable接口
class Person implements Serializable { String name; int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } protected Person deepClone() throws Exception { //序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); //反序列化 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (Person) ois.readObject(); } }
測試方法
public void testClone() throws Exception { Person person1 = new Person(); person1.setName("ccy"); person1.setAge(20); Person person2 = person1.deepClone(); System.out.println(person1.getName() == person2.getName()); }
可以看到兩個引用對象的地址并不同,成功實現了深拷貝
關于Java中淺拷貝和深拷貝該怎么理解就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。