La clonazione è un paradigma di programmazione di base. Il fatto che Java possa averlo implementato male in molti modi non diminuisce affatto la necessità di clonazione. Ed è facile implementare la clonazione che funzionerà come vuoi che funzioni, superficiale, profonda, mista, qualunque cosa. Puoi anche usare il nome clone per la funzione e non implementare Cloneable, se lo desideri.
Supponiamo che io abbia le classi A, B e C, dove B e C derivano da A. Se ho un elenco di oggetti di tipo A come questo:
ArrayList<A> list1;
Ora, quell'elenco può contenere oggetti di tipo A, B o C. Non sai che tipo sono gli oggetti. Quindi, non puoi copiare l'elenco in questo modo:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
Se l'oggetto è effettivamente di tipo B o C, non otterrai la copia corretta. E se A fosse astratto? Ora, alcune persone hanno suggerito questo:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
Questa è un'idea molto, molto cattiva. Cosa succede se aggiungi un nuovo tipo derivato? Cosa succede se B o C sono in un altro pacchetto e non hai accesso a loro in questa classe?
Quello che vorresti fare è questo:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
Molte persone hanno indicato perché l'implementazione Java di base di clone è problematica. Ma è facilmente superabile in questo modo:
In classe A:
public A clone() {
return new A(this);
}
In classe B:
@Override
public B clone() {
return new B(this);
}
In classe C:
@Override
public C clone() {
return new C(this):
}
Non sto implementando Cloneable, sto solo usando lo stesso nome di funzione. Se non ti piace, chiamalo qualcos'altro.