Che cosa è questa copia campo per campo fatto da Object.clone ()?
Domanda
In Effective Java, l'autore afferma che:
Se un implementa classe Cloneable, metodo clone di Object restituisce un campo per campo copia dell'oggetto; altrimenti si getta CloneNotSupportedException.
Quello che mi piacerebbe sapere è cosa intende con copia campo per campo. Vuol dire che se la classe ha X byte in memoria, sarà solo copiare quel pezzo di memoria? Se sì, allora posso assumere tutti i tipi di valore della classe originale verranno copiati al nuovo oggetto?
class Point implements Cloneable{
private int x;
private int y;
@Override
public Point clone() {
return (Point)super.clone();
}
}
Se Object.clone()
fa è un campo da campo copia della classe Point
, direi che non avrei bisogno di copiare i campi in modo esplicito x
e y
, essendo che il codice mostrato sopra sarà più che sufficiente per fare un clone della classe Point
. Cioè, il seguente pezzo di codice è ridondante:
@Override
public Point clone() {
Point newObj = (Point)super.clone();
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant
}
ho ragione?
Lo so riferimenti dell'oggetto clonato punterà automaticamente al punto in cui i riferimenti dell'oggetto originale indicavano, solo che non sono sicuro di quello che accade in particolare con i tipi di valore. Se qualcuno potrebbe affermare chiaramente ciò che specifica l'algoritmo di Object.clone()
è (in semplice linguaggio) sarebbe fantastico.
Soluzione
Sì, un campo da copia campo vuol dire che quando si crea il nuovo oggetto (clonato), la JVM copierà il valore di ogni campo dall'oggetto originale nello oggetto clonato. Purtroppo questo significa che si dispone di una copia. Se si desidera una copia completa, è possibile ignorare il metodo clone.
class Line implements Cloneable {
private Point start;
private Point end;
public Line() {
//Careful: This will not happen for the cloned object
SomeGlobalRegistry.register(this);
}
@Override
public Line clone() {
//calling super.clone is going to create a shallow copy.
//If we want a deep copy, we must clone or instantiate
//the fields ourselves
Line line = (Line)super.clone();
//assuming Point is cloneable. Otherwise we will
//have to instantiate and populate it's fields manually
line.start = this.start.clone();
line.end = this.end.clone;
return line;
}
}
Anche una cosa più importante circa la clonazione è, il costruttore dell'oggetto clonato non è mai invocato (solo i campi vengono copiati). Quindi, se il costruttore inizializza un oggetto esterno, o registra questo oggetto con qualche registro, quindi che non accadrà per l'oggetto clonato.
Io personalmente preferisco non usare la clonazione di Java. Invece genere creo i miei metodi "duplicazione".
Altri suggerimenti
Ciò significa una copia - i campi vengono copiati, ma se avete dei riferimenti, ciò che questi punti di non viene copiato - si avranno due riferimenti allo stesso oggetto, uno nel vecchio oggetto e uno in nuovo, oggetto clonato. Tuttavia, per i campi che hanno i tipi primitivi, il campo è dati stessi, in modo da ottenere copiati indipendentemente.
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant
che è di destra -. Questi sono ridondanti, dal momento che sono già stati copiati da clone di Object () Metodo
Pensare di esso come una copia dei dati è corretta. I tipi primitivi vengono copiati e riferimenti sono copiati in modo che puntano allo stesso oggetto. Ad esempio,
class A implements Cloneable {
Object someObject;
}
A a = new A();
a.someObject = new Object();
A cloneA = (A)a.clone();
assert a.someObject==cloneA.someObject;
Il clone esegue di default copia superficiale di valori. Per i valori primitivi, questo è sufficiente e non è necessario alcun lavoro supplementare.
Per gli oggetti, la copia superficiale mezzi copiando solo il riferimento. Pertanto, in questi casi è di solito necessario una copia profonda. L'eccezione di questo è quando il riferimento punta a un oggetto immutabile. oggetti immutabili non possono avere il loro stato apparente è cambiato, quindi i loro riferimenti possono essere copiati in sicurezza. Ad esempio, questo vale per stringa, intero Float, enumerazioni (se non fatto mutabili per errore).