Copia profunda de una matriz de objetos

Quiero hacer una copia profunda de una matriz de objetos usando un constructor.

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

Sin embargo, lo que tengo arriba por alguna razón no está funcionando. He automatizado las pruebas que ejecuto, y está fallando esas pruebas. Entonces hay un error aquí que no estoy seguro de qué se trata.

Lo que has implementado es una copia superficial . Para implementar una copia profunda , debe cambiar

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

a algo que asigna una copia de other.data[i] a data[i] . Cómo lo haces depende de la clase de Position . Las posibles alternativas son:

  • un constructor de copia:

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

  • un método de fábrica:

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

  • clon:

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

Notas:

  1. Lo anterior supone que el constructor de copia, el método de fábrica y el método de clonación implementan respectivamente el tipo de copia “correcta”, dependiendo de la clase de posición; vea abajo.
  2. El enfoque de clone solo funcionará si Position lo admite explícitamente, y esto generalmente se considera una solución inferior. Además, debe tener en cuenta que la implementación nativa de clone (es decir, el método Object.clone() ) hace una copia superficial.

De hecho, el problema general de implementar una copia profunda en Java es complicado. En el caso de la clase Position , se supondría que los atributos son todos tipos primitivos (por ejemplo, ints o dobles) y, por lo tanto, una copia profunda versus poco profunda es discutible. Pero si hay atributos de referencia, entonces debes confiar en el método copy constructor / factory method / clone para realizar el tipo de copiado que necesites. En cada caso, debe progtwigrse en. Y en el caso general (en el que debe tratar ciclos), es difícil y requiere que cada clase implemente métodos especiales.

Existe otra forma potencial de copiar una matriz de objetos. Si los objetos de la matriz son serializables , puede copiarlos usando ObjectOutputStream y ObjectInputStream serializar y luego deserializar la matriz. Sin embargo:

  • esto es caro,
  • solo funciona si los objetos son (transitivamente) serializables, y
  • los valores de cualquier campo transient no se copiarán.

No se recomienda copiar por serialización. Sería mejor apoyar la clonación o algún otro método.

En general, lo mejor es evitar la copia profunda en Java.

Finalmente, para responder a su pregunta sobre el funcionamiento del constructor de copias de clases de Position , espero que sea algo como esto:

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

Como dice @Turtle, no hay magia involucrada. Implementa un constructor (a mano) que inicializa su estado copiando de una instancia existente.

Cuando tu dices:

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

Solo está copiando una lista de referencias (suponiendo que se trata de una matriz de objetos). Si desea hacer una copia profunda, debe usar new para crear una nueva instancia de cada objeto en la matriz.

En lugar de decir:

 data[i]=other.data[i] 

Querrá hacer un constructor de copia para Position (en otras palabras, un constructor para Position que toma otra Position y copia los datos primitivos dentro de ella) y decir data[i]=new Position(other.data[i]);

Básicamente, su constructor de “copia profunda” PositionList es un constructor de copia, aunque el constructor de copia tiende a indicar una copia profunda, por lo que el parámetro deepCopy es innecesario.

Aquí hay una función que uso:

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

Solo funciona en arreglos con objetos con un solo nivel.

Esto debería hacer una copia “profunda”

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