Cópia profunda de uma matriz de objects

Eu quero fazer uma cópia profunda de uma matriz de objects usando um construtor.

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]; } 

No entanto, o que eu tenho acima por algum motivo não está funcionando. Eu tenho testes automatizados que eu executo, e está falhando nesses testes. Então há um erro aqui que não tenho certeza do que é.

O que você implementou é uma cópia superficial . Para implementar uma cópia profunda , você deve alterar

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

para alguma coisa que atribui uma cópia do other.data[i] aos data[i] . Como você faz isso depende da class Position . Possíveis alternativas são:

  • um construtor de cópia:

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

  • um método de fábrica:

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

  • clone:

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

Notas:

  1. Os itens acima assumem que o construtor de cópia, o método de fábrica e o método clone implementam, respectivamente, o tipo “certo” de cópia, dependendo da class Position; ver abaixo.
  2. A abordagem do clone só funcionará se a Position suportar explicitamente, e isso geralmente é considerado uma solução inferior. Além disso, você precisa estar ciente de que a implementação nativa do clone (ou seja, o método Object.clone() ) faz uma cópia superficial.

Na verdade, o problema geral de implementar a cópia profunda em Java é complicado. No caso da class Position , pode-se presumir que os atributos são todos tipos primitivos (por exemplo, ints ou doubles) e, portanto, uma cópia profunda versus superficial é irrelevante. Mas se houver atributos de referência, você terá que confiar no método construtor de cópia / método de fábrica / clone para fazer o tipo de cópia que você precisa. Em cada caso, precisa ser programado. E, no caso geral (onde você tem que lidar com ciclos), é difícil e exige que cada class implemente methods especiais.

Há uma outra maneira potencial de copiar uma matriz de objects. Se os objects na matriz forem serializáveis , você poderá copiá-los usando serialização ObjectOutputStream e ObjectInputStream e, em seguida, desserializar a matriz. Contudo:

  • isto é caro,
  • só funciona se os objects forem (transitivamente) serializáveis ​​e
  • os valores de qualquer campo transient não serão copiados.

Copiar por serialização não é recomendado. Seria melhor apoiar clonagem ou algum outro método.

Em suma, é melhor evitar a cópia profunda em Java.

Finalmente, para responder à sua pergunta sobre o construtor de cópia Position classs copy, espero que seja algo assim:

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

Como diz @Turtle, não há mágica envolvida. Você implementa um construtor (manualmente) que inicializa seu estado copiando de uma instância existente.

Quando voce diz:

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

Você está apenas copiando uma lista de referências (assumindo que esta é uma matriz de objects). Se você quiser fazer uma cópia profunda, precisará usar o new para criar uma nova instância de cada object na matriz.

Ao invés de dizer:

 data[i]=other.data[i] 

Você desejará fazer um construtor de cópia para Position (em outras palavras, um construtor para Position que assume outra Position e copia os dados primitivos dentro dela) e digamos data[i]=new Position(other.data[i]);

Basicamente, o seu construtor “cópia profunda”, o PositionList é um construtor de cópia, embora o construtor de cópia tenda a indicar uma cópia profunda, portanto, o parâmetro deepCopy é desnecessário.

Aqui está uma function que eu uso:

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

Ele só funciona em matrizes com objects com um único nível.

Isso deve fazer uma cópia “profunda”

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