Tadeu Cruz


Utilizando método clone() no Java

Descrição do problema.

Em um projeto que estava trabalhando tinha a necessidade de ao percorrer uma List pegar alguns Object e salvar em outra List para ser utilizado depois em outra lógica do código. O problema acontece quando fazia alteração no Object o valor da alteração "replicava" para o Object já salvo na List.

Exemplo do problema.

Class Pessoa

public class Pessoa {  
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public String toString() {
        return "Pessoa{" +
                "nome='" + nome + '\'' +
                '}';
    }
}

Class App

import java.util.ArrayList;  
import java.util.List;

public class App {  
    public static void main(String[] args) {
        Pessoa pessoa1 = new Pessoa();
        Pessoa pessoa2 = new Pessoa();
        List<Pessoa> listPrincipal = new ArrayList<>();
        List<Pessoa> listTemporaria = new ArrayList<>();

        pessoa1.setNome("Jose");
        pessoa2.setNome("Maria");

        listPrincipal.add(pessoa1);
        listPrincipal.add(pessoa2);

        for (Pessoa pessoa : listPrincipal){
            listTemporaria.add(pessoa);
            pessoa.setNome(pessoa.getNome().concat(" Alterado"));
        }

        System.out.println("Conteudos do listPrincipal");
        for (Pessoa pessoa : listPrincipal){
            System.out.println(pessoa);
        }

        System.out.println("Conteudos do listTemporaria");
        for (Pessoa pessoa : listTemporaria){
            System.out.println(pessoa);
        }

    }
}

Saída da Class App

Conteudos do listPrincipal  
Pessoa{nome='Jose Alterado'}  
Pessoa{nome='Maria Alterado'}  
Conteudos do listTemporaria  
Pessoa{nome='Jose Alterado'}  
Pessoa{nome='Maria Alterado'}  

Solução

Mesmo que no Java a passagem de variáveis seja por valor quando é um Object ele passar o valor da memória do mesmo. Para evitar esse tipo de problema podemos utilizar o método clone() para tal temos que implementar na classe Pessoa a interface Cloneable. Fincando conforme abaixo:

Class Pessoa com Cloneable

public class Pessoa implements Cloneable {  
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public String toString() {
        return "Pessoa{" +
                "nome='" + nome + '\'' +
                '}';
    }

    public Pessoa clone() {
        try {
            return (Pessoa) super.clone();
        } catch (CloneNotSupportedException e) {
            System.err.println("Class não suporte Cloneable");
            return this;
        }
    }
}

E para podemos utilizar o metodo clone() temos que fazer uma simples alteração no App, conforme abaixo:

Class App com a pequena modificação

import java.util.ArrayList;  
import java.util.List;

public class App {  
    public static void main(String[] args) {
        Pessoa pessoa1 = new Pessoa();
        Pessoa pessoa2 = new Pessoa();
        List<Pessoa> listPrincipal = new ArrayList<>();
        List<Pessoa> listTemporaria = new ArrayList<>();

        pessoa1.setNome("Jose");
        pessoa2.setNome("Maria");

        listPrincipal.add(pessoa1);
        listPrincipal.add(pessoa2);

        for (Pessoa pessoa : listPrincipal){
            listTemporaria.add(pessoa.clone());
            pessoa.setNome(pessoa.getNome().concat(" Alterado"));
        }

        System.out.println("Conteudos do listPrincipal");
        for (Pessoa pessoa : listPrincipal){
            System.out.println(pessoa);
        }

        System.out.println("Conteudos do listTemporaria");
        for (Pessoa pessoa : listTemporaria){
            System.out.println(pessoa);
        }
    }
}

Com essa alteração temos o seguinte resultado após executar.

Conteudos do listPrincipal  
Pessoa{nome='Jose Alterado'}  
Pessoa{nome='Maria Alterado'}  
Conteudos do listTemporaria  
Pessoa{nome='Jose'}  
Pessoa{nome='Maria'}  

Conclusão

A utilização do clone() ajuda bem o desenvolvedor já que faz copia bit a bit do Object que se encontra na memória. Porem nem tudo são flores, a utilização do clone() tem que ser feito com cuidado já que se Class que queremos clonar tem alguma herança temos que ir em todas as class e implementar o Cloneable e criar o método clone().

Referencia e boas dicas.

http://fragmentedpodcast.com/episodes/058/