Summary
淺克隆與深克隆對于JavaSE來說,是個難度系數比較低的概念,但不應該輕視它。
假設一個場景:對于某個list,代碼里并沒有任何對其的直接操作,但里面的元素的屬性卻被改變了,這可能就涉及到這個概念。
DescrOperator比較二者的地址會返回true。(不同引用,同一對象)
深克隆指則會copy一個新的對象并返回相應引用,即開辟了新的堆內存空間,因此使用“==” operator來比較兩者的地址時會返回false。(不同引用,不同對象)
淺克隆(shallow clone)
System.arraycoppy()
進行淺克隆。(你非得要用"=" foreach地clone也沒人攔著)jdk中顯式定義的clone操作基本上都使用:
1 System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
例如ArrayList中的clone()、Arrays.copyOf()等對具體數組的clone其實底層都是調用該方法。
1 package com.scv.test.clone; 2 3 public class ShallowCloneTest { 4 5 public static void main(String[] args) throws Exception { 6 Zerg z0 = new Zerg(); 7 Zerg z1 = z0; 8 System.out.驗證Shallow Clone深克隆(deep clone)
jdk中并沒有顯式定義深克隆,或者說并沒有直接提供工具類來進行。要讓你的自定義類支持深克隆,必須具備兩個條件:
- implements Cloneable interface.
- override clone() defined in java.lang.Object.
如果不實現Cloneable而直接override Object的clone(),則會拋出CloneNotSupportedException。
1 package com.scv.test.clone; 2 3 public class DeepCloneTest { 4 5 public static void main(String[] args) throws Exception { 6 CloneableZerg z0 = new CloneableZerg(); 7 CloneableZerg z1 = z0.clone(); 8 9 System.out.println("0. " + (z0 == z1));10 }11 12 }13 14 class CloneableZerg implements Cloneable{15 16 @Override17 public CloneableZerg clone() throws CloneNotSupportedException{18 return (CloneableZerg)super.clone();19 }20 }21 22 /* Output:23 0. false24 */驗證Deep Clone實際上,你可以自定義哪些成員變量(field)允許clone,哪些不允許(有點transient的感覺?)。
jdk中的實現:ArrayList中的淺克隆與深克隆
1 package com.scv.test.clone; 2 3 import java.util.ArrayList; 4 5 public class ArrayListCloneTest { 6 7 public static void main(String[] args) throws Exception { 8 CloneTarget t = new CloneTarget(); 9 10 ArrayList<CloneTarget> list0 = new ArrayList<CloneTarget>(1);11 list0.add(t);12 ArrayList<CloneTarget> list1 = (ArrayList<CloneTarget>) list0.clone();13 list0.get(0).setFieldA(20);14 15 System.out.println("0. " + (list0 == list1));16 System.out.println("1. " + (list0.get(0) == list1.get(0)));17 System.out.println("2. " + list1.get(0).getFieldA());18 }19 20 }21 22 class CloneTarget implements Cloneable{23 24 private int fieldA = 10;25 26 @Override27 public CloneTarget clone() throws CloneNotSupportedException{28 return (CloneTarget)super.clone();29 }30 31 public void setFieldA(int a){32 fieldA = a;33 }34 35 public int getFieldA(){36 return fieldA;37 }38 }39 40 /*41 * Output:42 * 0. false 43 * 1. true44 * 2. 2045 */Click Me操作說明:
- 創建一個ArrayList對象list0
- list0中加入一個對象t
- 克隆list0對象為list1
- 再修改list0中元素(即t)的屬性
結果說明:
- ArrayList實現了Cloneable接口,arraylist.clone()為深克隆,故list0與list1分別指向不同內存區域。
- ArrayList對象的clone()對于內部數組的元素僅為淺克隆,故list0中的元素(t)與list1中的元素為同一個,對list0元素的修改將影響到list1的元素。
新聞熱點
疑難解答