Pergunta

Existe alguma utilidade para clonagem profunda para coleções de java:

  • Arrays
  • listas
  • mapas

NOTA: prefiro alguma solução sem uso de serialização, mas com uso de Object.clone () método. Posso ter certeza de que o meu objeto personalizado irá implementar o método clone () e vai usar classes somente java-padrão que são cloneable ...

Foi útil?

Solução

Acho que a resposta verde anterior era ruim , por que você pode perguntar?

  • Ele adiciona um monte de código
  • Ela exige que você listar todos os campos a serem copiados e fazer isso
  • Isso não vai funcionar para listas quando usando clone () (Isto é o que clone () para HashMap diz: Retorna uma cópia superficial dessa instância HashMap:. As chaves e valuesthemselves não são clonados) assim que você acaba fazendo isso manualmente (isso me faz chorar)

Oh e pela maneira de serialização também é ruim, você pode ter que adicionar Serializable todo o lugar (isso também me faz chorar).

Então, qual é a solução:

Java Deep-Clonagem biblioteca A biblioteca de clonagem é uma pequena fonte, aberta (licença Apache) biblioteca java que no fundo clones objetos. Os objetos não têm para implementar a interface Cloneable. De forma efectiva, esta biblioteca pode objetos clone QUALQUER java. Ele pode ser usado ou seja, no cache implementações se você não quiser que o objeto em cache a ser modificado ou sempre que você deseja criar uma cópia em profundidade de objetos.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Confira no https://github.com/kostaskougios/cloning

Outras dicas

Todas as abordagens para copiar objetos em Java têm falhas graves:

Clone

  1. O clone () é protegido, então você não pode chamá-lo diretamente a menos que a classe em questão substitui-lo com um método público.
  2. clone () não chama o construtor. Qualquer construtor. Ele vai alocar a memória, atribuir o campo class interna (que você pode ler através getClass()) e copiar os campos do original.

Para mais problemas com clone (), consulte o item 11 do livro de Joshua Bloch " eficaz Java, Second Edition "

Serialize

Serialize é ainda pior; ele tem muitas das falhas de clone() e então alguns. Joshua tem um capítulo inteiro, com quatro itens para somente este tema.

Minha solução

A minha solução é adicionar uma nova interface para meus projetos:

public interface Copyable<T> {
    T copy ();
    T createForCopy ();
    void copyTo (T dest);
}

Os olhares código como este:

class Demo implements Copyable<Demo> {
    public Demo copy () {
        Demo copy = createForCopy ();
        copyTo (copy);
        return copy;
    }
    public Demo createForCopy () {
        return new Demo ();
    }
    public void copyTo (Demo dest)
        super.copyTo (dest);
        ...copy fields of Demo here...
    }
}

Infelizmente, eu tenho que copiar este código a todos os meus objetos, mas é sempre o mesmo código, para que eu possa usar um modelo de editor Eclipse. Vantagens:

  1. eu posso decidir qual construtor chamar e como inicializar qual campo.
  2. Inicialização acontece em uma ordem determinística (classe raiz para a aula exemplo)
  3. posso reutilizar objetos existentes e substituí-los
  4. Tipo de seguro
  5. singletons estadia singletons

Para os tipos de Java padrão (como coleções, etc), eu uso uma classe de utilitário que pode copiar os. Os métodos têm bandeiras e retornos de chamada, para que eu possa controlar a profundidade uma cópia deve ser.

Shallow clonagem de uma coleção é fácil, mas se você quiser clone profundo, uma biblioteca, provavelmente vai fazer melhor do que a mão de codificação-lo (desde que você deseja clonar os elementos dentro a coleção também) .

Assim como esta resposta , eu usei o clonador biblioteca e especificamente desempenho testados contra XStream (que pode 'clone', serialização então deserializing) e serialização binário. Embora XStream é muito rápido na serialização de / para xml, Cloner é muito mais rápido na clonagem:

0,0851 ms: XStream (clone, serialização / desserialização)
0,0223 ms: serialização binária (clone, serialização / desserialização)
0,0017 ms: cloner
* tempo médio para clonar um objeto simples (dois campos) e nenhum padrão, construtor público. Execute 10.000 vezes.

Além de ser rápido, aqui estão mais razões para escolher cloner:

  1. realiza uma profunda clone de qualquer objeto (mesmo aqueles que você não escreve a si mesmo)
  2. você não tem que manter o seu método clone () up-to-date cada vez que você adicionar um campo
  3. Você pode clonar objetos que não têm um construtor público padrão
  4. trabalhos com Primavera
  5. (otimização) não clone conhecido objetos imutáveis ??(como Integer, String, etc.)
  6. fácil de usar. Exemplo:

    cloner.deepClone (anyObject);

Eu sou o criador do lib Cloner, o que Brad apresentado. Esta é uma solução para a clonagem de objetos sem ter que escrever qualquer código extra (sem necessidade de objetos serializados ou clone impl () método)

É muito mais rápido que Brad disse, e, recentemente, eu enviei uma versão que é ainda mais rápido. Note-se que a implementação manualmente um clone () método será mais rápido do que lib clone, mas novamente você terá que escrever um monte de código.

Cloner lib tem funcionado muito bem para mim desde que eu estou usando-o em uma implementação de cache para um site com tráfego muito pesado (~ 1 milhão de pedidos / dia). O cache deve clonar cerca de 10 objetos por pedido. É bastante confiável e estável. Mas esteja ciente de que a clonagem não é sem risco. A lib pode ser configurado para println cada instância de classe que clona durante dev. Desta forma, você pode verificar se ele clona o que você acha que deveria clonar - gráficos de objeto pode ser muito profundo e pode conter referências a uma quantidade surpreendentemente grande de objetos. Com lib clone, você pode instruí-lo a não clone os objetos que você não quer, ou seja, singletons.

Uma forma geral para deep-clone uma coleção arbitrária é serializar-lo para um fluxo, em seguida, lê-lo de volta para uma nova coleção. Você será reidratação completamente novos objetos que não têm qualquer relação com os antigos, além de ser cópias idênticas.

Confira resposta de Bruno para um link para o Apache Commons utilidade serialização , que será muito útil se esse é o caminho que você decida tomar.

Uma possibilidade é usar serialização :

Apache Commons fornece SerializationUtils

Use a serialização e desserialização em seguida, mas esteja ciente de que esta abordagem funciona apenas com as classes Serializable sem campos transitórios. Além disso, seus singletons não será singletons mais.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top