Il metodo clone()
restituisce un nuovo oggetto il cui stato iniziale è una copia dell’oggetto su cui viene invocato.
Se si vuole che sia possibile copiare gli oggetti di una classe, la classe deve implementare l’interfaccia Cloneable
.
Il metodo clone()
che viene ereditato dalla classe Object
controlla prima di tutto che la classe dell’oggetto implementi l’interfaccia Cloneable
e in caso contrario lancia l’eccezione CloneNotSupportedException
, altrimenti crea un nuovo oggetto e lo inizializza con una copia degli attributi dell’oggetto originale; al termine restituisce un riferimento al nuovo oggetto.
Il metodo clone()
restituisce un riferimento di tipo Object
; per usare l’oggetto restituito bisogna fare un cast.
Gli array implementano l’interfaccia Cloneable
, quindi è possibile ottenere una copia di un array con il metodo clone()
.
int[] a = {1, 2, 3}; int[] b = (int[])a.clone();
Il metodo clone()
restituisce un Object
quindi bisogna fare un cast.
In genere una classe deve ridefinire il metodo clone()
per renderlo pubblico (quello ereditato è protected
).
Il metodo ridefinito di solito si limita a richiamare super.Clone()
, intercettando l’eccezione CloneNotSupportedException
che può essere lanciata.
Classe Quadrato con il metodo clone() che permette di copiare un quadrato.
public class Quadrato implements Cloneable { ... public Object clone() { try { Object ogg = super.clone(); return ogg; } catch(CloneNotSupportedException e ){ return null; } } }
Qualunque classe può creare una copia di un quadrato.
Quadrato q2 = (Quadrato) q1.clone();
Se una classe ha attributi che sono oggetti (quindi anche array) deve ridefinire clone()
in modo da creare una copia anche di questi oggetti; il metodo clone()
ereditato infatti non agisce in modo ricorsivo e per gli attributi che sono oggetti copia il riferimento (copia superficiale).
Se la classe Cerchio
ha un attributo centro della classe Punto
bisogna creare una copia del centro (anche la classe Punto
deve permettere di fare copie di oggetti).
public class Cerchio implements Cloneable { private Punto centro; private int raggio; ... public Object clone() { try { Cerchio c = (Cerchio)super.clone(); c.centro = (Punto)centro.clone(); return c; } catch(CloneNotSupportedException e ){ return null; } } }
Una classe dovrebbe clonare tutti i riferimenti agli oggetti modificabili che distribuisce in modo che altre classi non li possano modificare.
Per esempio un metodo della classe Cerchio
che restituisce il centro potrebbe essere:
public Punto getCentro() { return (Punto)centro.clone(); }