Copia profonda di un array di oggetti

Voglio fare una copia profonda di un array di oggetti usando un costruttore.

public class PositionList { private Position[] data = new Position[0]; public PositionList(PositionList other, boolean deepCopy) { if (deepCopy){ size=other.getSize(); data=new Position[other.data.length]; for (int i=0;i<data.length;i++){ data[i]=other.data[i]; } 

Tuttavia, ciò che ho sopra per qualche motivo non funziona. Ho eseguito test automatici che eseguo e non riescono a quei test. Quindi c’è un errore qui che non sono sicuro di cosa sia.

Quello che hai implementato è una copia superficiale . Per implementare una copia profonda , è necessario modificare

 data[i] = other.data[i]; 

a qualcosa che assegna una copia di other.data[i] ai data[i] . Il modo in cui lo fai dipende dalla class Position . Le possibili alternative sono:

  • un costruttore di copie:

    data[i] = new Position(other.data[i]);

  • un metodo di fabbrica:

    data[i] = createPosition(other.data[i]);

  • clone:

    data[i] = (Position) other.data[i].clone();

Gli appunti:

  1. Quanto sopra presuppone che il costruttore di copie, il metodo factory e il metodo clone implementino rispettivamente il tipo “giusto” di copia, a seconda della class Position; vedi sotto.
  2. L’approccio del clone funzionerà solo se Position lo supporta esplicitamente, e questa è generalmente considerata una soluzione inferiore. Inoltre, è necessario essere consapevoli che l’implementazione nativa di clone (ovvero il metodo Object.clone() ) fa una copia superficiale.

In effetti, il problema generale di implementare la copia profonda in Java è complicato. Nel caso della class Position , si presume che gli attributi siano tutti tipi primitivi (ad esempio, interi o doppi), e quindi una copia profonda o poco profonda è discutibile. Ma se ci sono attributi di riferimento, allora devi fare affidamento sul metodo costruttore / metodo di copia / metodo di copia per fare il tipo di copia che ti serve. In ogni caso ha bisogno di essere programmato. E nel caso generale (dove si hanno a che fare con i cicli) è difficile e richiede ad ogni class di implementare metodi speciali.

C’è un altro modo potenziale per copiare un array di oggetti. Se gli oggetti nell’array sono serializzabili , è ansible copiarli utilizzando ObjectOutputStream e ObjectInputStream serialize e quindi deserializzare l’array. Però:

  • questo è costoso,
  • funziona solo se gli oggetti sono (transitivamente) serializzabili, e
  • i valori di qualsiasi campo transient non verranno copiati.

La copia per serializzazione non è raccomandata. Sarebbe meglio supportare la clonazione o qualche altro metodo.

Tutto sumto, la copia profonda è meglio evitare in Java.

Infine, per rispondere alla tua domanda sulle funzioni di costruzione di copia delle classi Position , mi aspetto che si tratti di qualcosa del genere:

 public class Position { private int x; private int y; ... public Position(Position other) { this.x = other.x; this.y = other.y; } ... } 

Come dice @Turtle, non c’è nulla di magico. Si implementa un costruttore (a mano) che inizializza il suo stato copiando da un’istanza esistente.

Quando dici:

 data[i]=other.data[i]; 

Stai semplicemente copiando un elenco di riferimenti (supponendo che si tratti di una serie di oggetti). Se vuoi fare una copia profonda, devi usare new per creare una nuova istanza di ogni object nella matrice.

Invece di dire:

 data[i]=other.data[i] 

Dovrai creare un costruttore di copia per Position (in altre parole, un costruttore per Posizione che prende in un’altra Position e copia i dati primitivi al suo interno) e dire data[i]=new Position(other.data[i]);

Fondamentalmente il tuo costruttore di “deep copy” il PositionList è un costruttore di copie, sebbene il costruttore di copie deepCopy di indicare una copia profonda, quindi il parametro deepCopy non è necessario.

Ecco una funzione che utilizzo:

 function copy(arr) { return arr .map(x => Object .keys(x) .reduce((acc, y) => { acc[y] = x[y] return acc }, {})) } 

Funziona solo su array con oggetti con un singolo livello.

Questo dovrebbe fare una copia “profonda”

 int [] numbers = { 2, 3, 4, 5}; int [] numbersClone = (int[])numbers.clone();