拷貝就是拷貝指向對象的指針,意思就是說:拷貝出來的目標對象的指針和源對象的指針指向的記憶體空間是同一塊空間,淺拷貝只是一種簡單的拷貝,讓幾個對象公用一個記憶體,然而當記憶體銷毀的時候,指向這個記憶體空間的所有指針需要重新定義,不然會造成野指針錯誤。
基本介紹
- 中文名:淺拷貝
- 外文名:shallow copy
- 學科:軟體工程
- 定義:按位拷貝對象
- 特點:對象公用一個記憶體
- 有關術語:拷貝構造函式
簡介,深拷貝與延遲拷貝,拷貝構造函式,代碼示例,
簡介
淺拷貝是按位拷貝對象,它會創建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是記憶體地址(引用類型),拷貝的就是記憶體地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象。即默認拷貝構造函式只是對對象進行淺拷貝複製(逐個成員依次拷貝),即只複製對象空間而不複製資源。
一般情況下,只需使用系統提供的淺拷貝構造函式即可,但是,如果對象的數據成員包括指向堆空間的指針,就不能使用這種拷貝方式,因為兩個對象都擁有同一個資源,對象析構時,該資源將經歷兩次資源返還,此時必須自定義深拷貝構造函式,為創建的對象分配堆空間,否則會出現動態分配的指針變數懸空的情況。
深拷貝與延遲拷貝
深拷貝會拷貝所有的屬性,並拷貝屬性指向的動態分配的記憶體。當對象和它所引用的對象一起拷貝時即發生深拷貝。深拷貝相比於淺拷貝速度較慢並且花銷較大。
延遲拷貝是淺拷貝和深拷貝的一個組合,實際上很少會使用。 當最開始拷貝一個對象時,會使用速度較快的淺拷貝,還會使用一個計數器來記錄有多少對象共享這個數據。當程式想要修改原始的對象時,它會決定數據是否被共享(通過檢查計數器)並根據需要進行深拷貝。延遲拷貝從外面看起來就是深拷貝,但是只要有可能它就會利用淺拷貝的速度。當原始對象中的引用不經常改變的時候可以使用延遲拷貝。由於存在計數器,效率下降很高,但只是常量級的開銷。而且, 在某些情況下, 循環引用會導致一些問題。
拷貝構造函式
在C+ +面向對象程式設計中,通過構造函式對對象進行初始化,它可以為對象在計算機記憶體中開闢記憶體空間,也可以為對象的數據成員提供初始值。構造函式是一個與類同名,沒有返回值的特殊成員函式,每當創建一個對象時(包括使用new動態創建對象),編譯系統就會自動調用構造函式。構造函式象類以外的一般函式和類成員函式一樣可以重載和帶預設參數,構造函式的重載為對象的生成提供了各種靈活的手段。構造函式分為預設構造函式(默認構造函式)和用戶自定義構造函式。當程式設計師沒有定義構造函式時,系統會提供一個無參的預設構造函式。如果用戶自定義了一個構造函式,編譯器提供的預設構造函式就自動消失了。
拷貝構造函式的功能是用一個已有的對象來初始化一個被創建的同類的對象,是一種特殊的構造函式,具有一般構造函式的所有特性,其形參是本類對象的引用。用戶可以根據自己實際問題的需要定義特定的拷貝構造函式,以實現同類對象之間數據成員的傳遞。如果用戶沒有聲明類的拷貝構造函式,系統就會自動生成一個預設拷貝構造函式,這個預設拷貝構造函式的功能是把初始對象的每個數據成員的值都複製到新建立的對象中。
代碼示例
public class Subject { private String name; public Subject(String s) { name = s; } public String getName() { return name; } public void setName(String s) { name = s; } }public class Student implements Cloneable { // 對象引用 private Subject subj; private String name; public Student(String s, String sub) { name = s; subj = new Subject(sub); } public Subject getSubj() { return subj; } public String getName() { return name; } public void setName(String s) { name = s; } /** * 重寫clone()方法 * @return */ public Object clone() { //淺拷貝 try { // 直接調用父類的clone()方法 return super.clone(); } catch (CloneNotSupportedException e) { return null; } } }