Question:
I am seeking to clone an object that contains anarray of the type float[][] which in turn contains primitive types. Using super.clone() and a clonable interface in the class has resulted in a shallow copy. Do I need to make the array an array of Objects and deep copy?
Answer:
The default clone()
method is implemented in native code in the fundamental java.lang.Object class. It performs the equivalent of a memcpy()
operation, which in C would cause any pointers to be copied directly. The effect in Java is for all references to point to the same objects and for primitive types to be copied. This results in a shallow copy. A deep copy is where true copies of all references are made by creating a new object and performing a deep copy of the original object. If you want clone()
to perform a deep copy, you have to implement it yourself. The following example makes clear the difference between a deep copy and a shallow copy, as well as showing that the default clone()
method copies references, rather than creating new objects with equivalent values.
public final class CloneExample { public static class ShallowCopy implements Cloneable { // I'm using an int array so I don't have to do print formatting. public int[][] data = { { 0, 1 }, { 1, 0 } }; public String toString() { StringBuffer buffer = new StringBuffer(); int row, column, d[]; for(row = 0; row < data.length; ++row) { d = data[row]; for(column = 0; column < d.length; ++column) { buffer.append(d[column]); buffer.append(' '); } buffer.append(' '); } return buffer.toString(); } public void setValue(int row, int column, int value) { data[row][column] = value; } // Performs a default shallow copy public Object clone() throws CloneNotSupportedException { return super.clone(); } } public static class DeepCopy extends ShallowCopy { // Explicitly performs a deep copy public Object clone() throws CloneNotSupportedException { int row; DeepCopy copy = new DeepCopy(); copy.data = new int[data.length][]; for(row=0; row < data.length; ++row) { copy.data[row] = new int[data[row].length]; System.arraycopy(data[row], 0, copy.data[row], 0, data[row].length); } return copy; } } public static final void main(String[] args) { ShallowCopy shallow = new ShallowCopy(); ShallowCopy shallowClone; DeepCopy deep = new DeepCopy(); DeepCopy deepClone; System.out.println("ShallowCopy Original Data"); System.out.println(shallow.toString()); try { shallowClone = (ShallowCopy)shallow.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); return; } // The clone should have the same data System.out.println("ShallowCopy Clone Data"); System.out.println(shallowClone.toString()); // In a shallow copy, if we alter the original data, it should // be reflected in the cloned data. shallow.setValue(0, 1, 0); shallow.setValue(1, 0, 0); System.out.println("ShallowCopy Original Data"); System.out.println(shallow.toString()); System.out.println("ShallowCopy Clone Data"); System.out.println(shallowClone.toString()); // Why was the data identical? Because the shallow copy caused // the clone data to reference the same array as the original. if(shallow.data == shallowClone.data) System.out.println( "The original array and cloned array are the same object!"); else System.err.println("Unexpected result!"); System.out.println("DeepCopy Original Data"); System.out.println(deep.toString()); try { deepClone = (DeepCopy)deep.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); return; } // The clone should have the same data System.out.println("DeepCopy Clone Data"); System.out.println(deepClone.toString()); // In a deep copy, if we alter the original data, it should // NOT be reflected in the cloned data. deep.setValue(0, 1, 0); deep.setValue(1, 0, 0); System.out.println("DeepCopy Original Data"); System.out.println(deep.toString()); System.out.println("DeepCopy Clone Data"); System.out.println(deepClone.toString()); // The data was not identical because the deep copy created // an entirely new array. if(deep.data != deepClone.data) System.out.println( "The original array and cloned array are NOT the same object!"); else System.err.println("Unexpected result!"); }}