You need to implement the Cloneable interface when overriding clone, Cloneable does not define any methods.
What is the meaning of that cloneable?
If a class implements the Clonable,object clone method, it can return a domain-wise copy of the object, otherwise it will throw clonenotsupportedexception.
Typically, an interface is implemented to indicate the behavior of a class.
The Cloneable interface changes the behavior of the protected method in the superclass.
This is an atypical usage and is not worthy of imitation.
Well, since we've covered the Clone method, we need to follow some conventions:
- X.clone ()! = x;
- X.clone (). GetClass () = X.getclass ();
- X.clone (). equals (x);
In addition, we must ensure that the clone result does not affect the original object while guaranteeing the Clone method's contract.
For example, in the following case, there is no overwrite clone method, directly get Super.clone () Result:
import java.util.Arrays;public class Stack implements Cloneable { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { this.elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; } public boolean isEmpty() { return size == 0; } // Ensure space for at least one more element. private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); }}
As a result, the elements of the clone result and the elements of the original object refer to the same array.
In this case, overwrite the Clone method and ensure that the original object is not harmed:
@Overridepublic Stack clone() { try { Stack result = (Stack) super.clone(); result.elements = elements.clone(); return result; } catch (CloneNotSupportedException e) { throw new AssertionError(); }}
Although the elements was taken out of the clone once, but the premise of this approach is that elements is not final.
It's normal. However, clone cannot be compatible with immutable field referencing mutable objects.
If an element of an array is a reference type, the problem still occurs when an element changes.
Here, for example Hashtable, the elements in Hashtable are entry with their inner classes.
private static class Entry<K,V> implements Map.Entry<K,V> { int hash; final K key; V value; Entry<K,V> next; protected Entry(int hash, K key, V value, Entry<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } //..}
If you clone the elements directly as in the stack example, the hashtable of the clone will change when a entry changes.
So the hashtable is so covered with clone:
/** * Creates a shallow copy of this hashtable. All the structure of the * hashtable itself is copied, but the keys and values are not cloned. * This is a relatively expensive operation. * * @return a clone of the hashtable */public synchronized Object clone() { try { Hashtable<K,V> t = (Hashtable<K,V>) super.clone(); t.table = new Entry[table.length]; for (int i = table.length ; i-- > 0 ; ) { t.table[i] = (table[i] != null) ? (Entry<K,V>) table[i].clone() : null; } t.keySet = null; t.entrySet = null; t.values = null; t.modCount = 0; return t; } catch (CloneNotSupportedException e) { // this shouldn‘t happen, since we are Cloneable throw new InternalError(); }}
Since clone can cause many problems, there are two suggestions:
- Do not extend the Cloneable interface
- Classes designed for inheritance do not implement the Cloneable interface
Effective Java-Overwrite clone with care