sexta-feira, 14 de dezembro de 2012

Clonando um objeto

De forma geral quando falamos em clonagem, estamos querendo dizer que estamos querendo obter uma cópia do objeto original. A classe Object possui um método denominado .clone() que cria e retorna uma cópia do objeto em questão.

O que vamos ver aqui é que o que se quer dizer como cópia não é necessariamente o que poderíamos esperar. Para que este método funcione, é necessário que o objeto implemente a interface Cloneable. Se ele não implementar é gerada uma exceção CloneNotSupportedException. Todos os arrays implementam esta interface.

Esse método cria uma nova instância do objeto e inicializa todos os campos com o mesmo conteúdo dos respectivos campos. Os conteúdos dos campos não são clonados. A documentação do Java caracteriza esta cópia como sendo "shallow copy". Não é uma "deep copy". Com isto queremos dizer que se a classe contem somente campos primitivos ou referência para objetos imutáveis, o objeto clonado será completamente clonado.

Como assim?

Exemplo 1)
Class Classe1 implements Cloneable {
   String nome;
   int inteiro;
   boolean boleano;
}

public Class
Classe1 c1 = new Classe1();
c1.nome = "nome original";
c1.inteiro = 1;
c2.booleano = true;
Classe1 c2 = c1.clone();
c2.inteiro = 2;
System.out

Campos mutáveis (como classes internas) que estão dentro da estrutura ("deep") do objeto ao serem clonados, não são criados novos objetos, somente é copiada a referência, portanto podemos ter comportamento que podem parecer inesperados como no exemplo abaixo:

Exemplo 2)
Class Campo {
   String campo1;
   boolean campo2;
}

class Classe2 implements Cloneable {
   String nome;
   int inteiro;
   boolean boleano;
   Campo campo;  
}

Classe2 c1 = new Classe1();
Classe2 c2 = c1.clone();
c1.campo.campo1 = "novo valor"

Para resolver isto temos que tratar estes objetos, criando clones deles também.

Vamos ver um exemplo, primeiro fazendo tudo certo, isto é, implementando "deep cloning" - copiando os atributos e os objetos encapsulados. Cada exemplo tem duas classes: uma funcionario que será clonada e outra que gera o exemplo.

Criei um objeto func1, clone este objeto para func2. Alterei os campos e consigo ver que os dois são independentes. A saída de Exemplo é:


Vamos ver agora uma implementação onde não foi clonado o objeto interno explicitamente.

 Vamos ver o que acontece se tento alterar o endereço de fun2. Veja o resultado da cidade para func1 e func2:
Alterei func2 e o resultado apareceu em func1. Por quê?
Porque como o objeto interno não é clonado, somente a referência do objeto é clonada, o que significa que o objeto endereco de func1 e func2 são os mesmos. Uma alteração em um reflete no outro.

 

Nenhum comentário:

Postar um comentário