segunda-feira, 25 de maio de 2020

Dicas de Programação: Como copiar um objeto "bit a bit" em Java?

Vocês já tiveram um problema desses?

Eu tenho uma classe Identificador que possue uma propriedade chamada codigo do tipo String:

public class Identificador implements Serializable {
       public String codigo;
       
       public Identificador(String codigo) {
               this.codigo = codigo;
       }

       public String toString() {
              return "[Identificador.codigo = " + codigo + "]";
       }
}

Eu crio cinco instâncias deste objeto e guardo em um ArrayList:

ArrayList<Identificador> lista = new ArrayList<>();
for (int i = 0; i < 5; i++) {
      lista.add(new Identificador("teste_" + i));
}

Agora eu quero criar um clone deste ArrayList para preservar os dados originais:

ArrayList<Identificador> listaClonada = lista.clone();

Mexo no valor primeiro objeto da lista clonada:

listaClonada.get(0).codigo = "meu_codigo";

Removo o último item desta lista:

listaClonada.remove(4);

Imprimo as duas listas para ver os seus valores:

System.out.println(lista);
System.out.println(listaClonada);

E veja, ele mudou o valor que mudei no outro ArrayList!!!

Por que isso acontece?

Porque o método clone copiou a instância do ArrayList, mas este não copia as instâncias dos itens internos. Uma das maneiras de "copiar tudo" é "serializar" os objetos e usar instruções de "stream":

ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(byteArray);
outputStream.writeObject(lista);
outputStream.flush();
ObjectInputStream inputStream = new ObjectInputStream(new 
       ByteArrayInputStream(byteArray.toByteArray()));
ArrayList<Identificador> listaClonada = (ArrayList<Identificador>)inputStream.readObject();
outputStream.close();
inputStream.close();

Isso é mais ou menos o que o SerializationUtils.clone do Apache Commons faz.

Tomara que isso ajude alguém... (é que deu um trabalhão para escrever :P)

Até mais!