I'm reading on Joshua Bloch's Effective Java, 2nd edition, Item 11: Override clone judiciously.
On page 56, he is trying to explain that when we override clone()
for some classes (like collection classes), we must copy the internals of it. He then gives the example of designing a class Stack
:
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {...}
public void push(Object e) {...}
public Object pop() {...}
private void ensureCapacity() {...} //omitted for simplicity
}
He claims that if we simply use super.clone()
to clone a Stack
, the resulting Stack instance "will have the correct value in its size field, but its elements field will refer to the same array as the original Stack instance. Modifying the original will destroy the invariants in the clone and vice versa. You will quickly find that your program produces nonsensical results or throws a NullPointerException."
Now that seems fair. But he then gives an example of the "correct implementation", which confuses me:
@Override public Stack clone() {
try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
Now how is that different from super.clone()
? I know, the new Stack.element
will be a different reference than the old one and all; but the "internals" of the array are still the same, aren't they? The actual elements of the array result.element
still point to the original Object
references. That could still result in destroying the invariants of the clone when changing the original, or vice versa, couldn't it? Am I missing anything?