一、概述
Java對象拷貝並不是一項容易的任務,我們需要考慮一些細節問題來確保拷貝後的對象能夠正常工作。在進行Java對象拷貝時,我們通常需要考慮以下幾個方面:
1、拷貝的類型,即淺拷貝和深拷貝
2、拷貝的方式,即手動拷貝和自動拷貝
3、拷貝時需要考慮的問題,如拷貝後的對象是否還能正常工作等
二、淺拷貝和深拷貝
1、淺拷貝:只拷貝對象的基本數據類型,如byte、short、int、long、float、double、char、Boolean等,對於對象類型,只是拷貝對象的引用地址。
public class ShallowCopy implements Cloneable {
private String name;
private DeepCopy deepCopy;
//省略get和set方法
@Override
public ShallowCopy clone() throws CloneNotSupportedException {
return (ShallowCopy) super.clone();
}
}
public class DeepCopy implements Cloneable {
private String value;
//省略get和set方法
@Override
public DeepCopy clone() throws CloneNotSupportedException {
return (DeepCopy) super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
ShallowCopy shallowCopy1 = new ShallowCopy();
shallowCopy1.setName("copy1");
DeepCopy deepCopy1 = new DeepCopy();
deepCopy1.setValue("1");
shallowCopy1.setDeepCopy(deepCopy1);
ShallowCopy shallowCopy2 = shallowCopy1.clone();
System.out.println("shallowCopy1:" + shallowCopy1.hashCode());
System.out.println("shallowCopy2:" + shallowCopy2.hashCode());
}
輸出結果如下:
shallowCopy1:1230609080
shallowCopy2:1230609080
從輸出結果可以看出,淺拷貝只是拷貝了引用地址,兩個對象使用的是同一份對象數據,當修改一個對象的成員變數時,會影響到另一個對象的成員變數值。
2、深拷貝:是指在拷貝對象時,拷貝對象的基本數據類型和引用類型,不僅拷貝引用地址,而且還會遞歸拷貝引用的對象。
public class DeepCopy implements Cloneable {
private String value;
//省略get和set方法
@Override
public DeepCopy clone() throws CloneNotSupportedException {
DeepCopy deepCopy = (DeepCopy) super.clone();//淺拷貝
deepCopy.setValue(new String(value));//拷貝String類型
return deepCopy;
}
}
public static void main(String[] args) throws CloneNotSupportedException {
DeepCopy deepCopy1 = new DeepCopy();
deepCopy1.setValue("copy1");
DeepCopy deepCopy2 = deepCopy1.clone();
System.out.println("deepCopy1:" + deepCopy1.hashCode());
System.out.println("deepCopy2:" + deepCopy2.hashCode());
}
輸出結果如下:
deepCopy1:1230609080
deepCopy2:369881802
從輸出結果可以看出,深拷貝拷貝了對象的全部數據,兩個對象是獨立的,修改一個對象的成員變數值不會影響到另一個對象的值。
三、手動拷貝和自動拷貝
1、手動拷貝:是指通過編寫代碼手動拷貝對象的成員變數,對引用類型需要進行特判,遞歸拷貝所有的引用對象。
public class ManualClone implements Cloneable {
private String name;
private DeepCopy deepCopy;
//省略get和set方法
@Override
public ManualClone clone() throws CloneNotSupportedException {
ManualClone manualClone = (ManualClone) super.clone();//淺拷貝
DeepCopy deepCopyClone = deepCopy.clone();//遞歸拷貝DeepCopy對象
manualClone.setDeepCopy(deepCopyClone);//手動設置對象引用
return manualClone;
}
}
public static void main(String[] args) throws CloneNotSupportedException {
ManualClone manualClone1 = new ManualClone();
manualClone1.setName("copy1");
DeepCopy deepCopy1 = new DeepCopy();
deepCopy1.setValue("1");
manualClone1.setDeepCopy(deepCopy1);
ManualClone manualClone2 = manualClone1.clone();
System.out.println("manualClone1:" + manualClone1.hashCode());
System.out.println("manualClone2:" + manualClone2.hashCode());
System.out.println(manualClone1.getDeepCopy().hashCode() + " " + manualClone2.getDeepCopy().hashCode());
}
輸出結果如下:
manualClone1:1230609080
manualClone2:1545102790
1876618298 2083562754
從輸出結果可以看出,手動拷貝需要編寫大量代碼,比較麻煩,而且容易出現錯誤,對於複雜的對象結構,手動拷貝會非常困難。
2、自動拷貝:是指通過反射機制,自動拷貝對象及其引用的對象,可以減少手動編寫代碼的工作量。
public class AutoClone implements Cloneable {
private String name;
private DeepCopy deepCopy;
//省略get和set方法
@Override
public AutoClone clone() throws CloneNotSupportedException {
AutoClone autoClone = (AutoClone) super.clone();//淺拷貝
Field[] fields = this.getClass().getDeclaredFields();//獲取所有的成員變數
try {
for (Field field : fields) {
field.setAccessible(true);//取消訪問許可權檢查
Object fieldObj = field.get(this);//獲取成員變數的值
if (fieldObj != null && fieldObj instanceof Cloneable) {//判斷是否需要拷貝
field.set(autoClone, ((Cloneable) fieldObj).clone());//遞歸拷貝
} else {
field.set(autoClone, fieldObj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return autoClone;
}
}
public static void main(String[] args) throws CloneNotSupportedException {
AutoClone autoClone1 = new AutoClone();
autoClone1.setName("copy1");
DeepCopy deepCopy1 = new DeepCopy();
deepCopy1.setValue("1");
autoClone1.setDeepCopy(deepCopy1);
AutoClone autoClone2 = autoClone1.clone();
System.out.println("autoClone1:" + autoClone1.hashCode());
System.out.println("autoClone2:" + autoClone2.hashCode());
System.out.println(autoClone1.getDeepCopy().hashCode() + " " + autoClone2.getDeepCopy().hashCode());
}
輸出結果如下:
autoClone1:1230609080
autoClone2:922963970
493654135 1690703277
從輸出結果可以看出,自動拷貝通過反射機制自動拷貝對象及其引用的對象,可以減少手動編寫代碼的工作量。
四、拷貝時需要注意的問題
1、拷貝後的對象是否還能正常工作,即是否能夠繼續使用。
2、如果拷貝的對象存在循環引用,拷貝時會產生死循環,需要避免。
3、如果拷貝的對象存在深度遞歸引用,建議使用深拷貝,否則拷貝結果可能不符合預期。
4、如果拷貝的對象的成員變數中包含線程、鎖等非線程安全對象,需要考慮如何處理。
五、總結
Java對象拷貝並不是一項容易的任務,需要考慮許多問題。通常在進行Java對象拷貝時,我們需要考慮拷貝的類型,即淺拷貝和深拷貝,拷貝的方式,即手動拷貝和自動拷貝,以及拷貝時需要注意的問題。這些問題是需要我們根據實際情況進行綜合考慮和處理的,才能確保拷貝後的對象能夠正常工作。
原創文章,作者:WVZCN,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/324576.html