1、實現Cloneable接口表明該類的對象是允許克隆的。
2、允許克隆的意思是:可以調用clone()方法。
3、深拷貝還是淺拷貝,取決於如何重寫Object的clone()方法。
4、原對象和克隆對象的關系:
深拷貝:陽關道和獨木橋;
淺拷貝:藕斷絲連。
上面的第二點解釋一下,如果沒有實現Cloneable就調用clone()方法,會拋出異常。看下Object源碼就知道了:
1 protected Object clone() throws CloneNotSupportedException { 2 if (!(this instanceof Cloneable)) {//這里會檢查是否是Cloneable的實例 3 throw new CloneNotSupportedException( 4 "Class " + getClass().getName() +" doesn't implement Cloneable"); 5 } 6 7 return internalClone(); 8 }
下面舉一個深拷貝的例子:
ArrayList的clone()方法:
1 //深拷貝 2 public Object clone() { 3 try { 4 ArrayList<?> v = (ArrayList<?>) super.clone(); 5 //新開辟一個內存空間給ArrayList的對象成員Object[] elementData; 6 v.elementData = Arrays.copyOf(elementData, size); 7 v.modCount = 0; 8 return v; 9 } catch (CloneNotSupportedException e) { 10 // this shouldn't happen, since we are Cloneable 11 throw new InternalError(e); 12 } 13 } 14 //transient Object[] elementData;
這樣得到新的ArrayList對象,則是一個完全獨立的對象,包括對象屬性成員和原來對象沒有任何聯系。你走你的陽關道,我走我的獨木橋,你以后做什么事都影響不了我。這就是深拷貝。
如果把上面的深拷貝改成淺拷貝,將會變成:
1 //淺拷貝 2 public Object clone() { 3 try { 4 ArrayList<?> v = (ArrayList<?>) super.clone(); 5 //有公用的對象成員elementData,它就是連接兩個對象的罪魁禍首。 6 v.elementData = elementData; 7 v.modCount = 0; 8 return v; 9 } catch (CloneNotSupportedException e) { 10 // this shouldn't happen, since we are Cloneable 11 throw new InternalError(e); 12 } 13 } 14 //transient Object[] elementData;
使用上面這個淺拷貝的clone()方法,原對象和克隆對象各自的對象成員elementData指向同一塊內存地址,藕斷絲連,相互影響着。你受傷了,我就難過;你過的開心,我就默默祝福你;你想我的時候,我也在想你。這就是淺拷貝。
補充:如果A的對象成員屬性是自己定義的類型(記為B),A想要深拷貝,需要依靠B的深拷貝clone()方法。
參考書籍:Effective Java(第2版)
