java数组深拷贝和浅拷贝_java中的深拷贝与浅拷贝(值类型 vs 引用类型)
對象賦值
賦值是日常編程過程中最常見的操作,最簡單的比如:
Student codeSheep = new Student(); Student codePig = codeSheep;
嚴格來說,這種不能算是對象拷貝,因為拷貝的僅僅只是引用關系,并沒有生成新的實際對象:
淺拷貝
淺拷貝屬于對象克隆方式的一種,重要的特性體現在這個?「淺」?字上。
比如我們試圖通過studen1實例,拷貝得到student2,如果是淺拷貝這種方式,大致模型可以示意成如下所示的樣子:
很明顯,值類型的字段會復制一份,而引用類型的字段拷貝的僅僅是引用地址,而該引用地址指向的實際對象空間其實只有一份。
深拷貝
深拷貝相較于上面所示的淺拷貝,除了值類型字段會復制一份,引用類型字段所指向的對象,會在內存中也創建一個副本
淺拷貝代碼實現
還以上文的例子來講,我想通過student1拷貝得到student2,淺拷貝的典型實現方式是:讓被復制對象的類實現Cloneable接口,并重寫clone()方法即可。
以上面的Student類拷貝為例:
public class Student implements Cloneable { private String name; // 姓名 private int age; // 年齡 private Major major; // 所學專業 @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } // ... 其他省略 ... }
public class Test { public static void main(String[] args) throws CloneNotSupportedException { Major m = new Major("計算機科學與技術",666666); Student student1 = new Student( "CodeSheep", 18, m ); // 由 student1 拷貝得到 student2 Student student2 = (Student) student1.clone(); System.out.println( student1 == student2 ); System.out.println( student1 ); System.out.println( student2 ); System.out.println( "\n" ); // 修改student1的值類型字段 student1.setAge( 35 ); // 修改student1的引用類型字段 m.setMajorName( "電子信息工程" ); m.setMajorId( 888888 ); System.out.println( student1 ); System.out.println( student2 ); } }
運行結果:
從結果可以看出:
student1==student2打印false,說明clone()方法的確克隆出了一個新對象;
修改值類型字段并不影響克隆出來的新對象,符合預期;
而修改了student1內部的引用對象,克隆對象student2也受到了波及,說明內部還是關聯在一起的
深拷貝代碼實現
深度遍歷式拷貝
雖然clone()方法可以完成對象的拷貝工作,但是注意:clone()方法默認是淺拷貝行為,就像上面的例子一樣。若想實現深拷貝需覆寫?clone()方法實現引用對象的深度遍歷式拷貝,進行地毯式搜索。
所以對于上面的例子,如果想實現深拷貝,首先需要對更深一層次的引用類Major做改造,讓其也實現Cloneable接口并重寫clone()方法:
public class Major implements Cloneable { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } // ... 其他省略 ... }
其次我們還需要在頂層的調用類中重寫clone方法,來調用引用類型字段的clone()方法實現深度拷貝,對應到本文那就是Student類:
public class Student implements Cloneable { @Override public Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); student.major = (Major) major.clone(); // 重要!!! return student; } // ... 其他省略 ... }
這時候上面的測試用例不變,運行可得結果:
很明顯,這時候student1和student2兩個對象就完全獨立了,不受互相的干擾。
利用反序列化實現深拷貝
利用反序列化技術,我們也可以從一個對象深拷貝出另一個復制對象,而且在解決多層套娃式的深拷貝問題時效果出奇的好。
所以我們這里改造一下Student類,讓其clone()方法通過序列化和反序列化的方式來生成一個原對象的深拷貝副本:
public class Student implements Serializable { private String name; // 姓名 private int age; // 年齡 private Major major; // 所學專業 public Student clone() { try { // 將對象本身序列化到字節流 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream( byteArrayOutputStream ); objectOutputStream.writeObject( this ); // 再將字節流通過反序列化方式得到對象副本 ObjectInputStream objectInputStream = new ObjectInputStream( new ByteArrayInputStream( byteArrayOutputStream.toByteArray() ) ); return (Student) objectInputStream.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } // ... 其他省略 ... }
當然這種情況下要求被引用的子類(比如這里的Major類)也必須是可以序列化的,即實現了Serializable接口:
public class Major implements Serializable { // ... 其他省略 ... }
這時候測試用例完全不變,直接運行,也可以得到如下結果:
很明顯,這時候student1和student2兩個對象也是完全獨立的,不受互相的干擾,深拷貝完成。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的java数组深拷贝和浅拷贝_java中的深拷贝与浅拷贝(值类型 vs 引用类型)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 视觉开发需要什么程度的数学_角度的概念在
- 下一篇: mysql数据库属性_mysql - 数
