Eu estou querendo saber se existe uma maneira recomendada de fazer clone / cópia profunda da instância em java.
Tenho 3 soluções em mente, mas posso sentir falta de algumas e gostaria de ter sua opinião
editar: inclua a proposta de Bohzo e refine a pergunta: trata-se mais de clonagem profunda do que de clonagem superficial.
Faça Você Mesmo:
codifique o clone manualmente, após as propriedades, e verifique se as instâncias mutáveis também são clonadas.
pro:
- controle do que será executado
-
contras de execução rápida :
- tedioso para escrever e manter
- propenso a erros (falha de copiar / colar, falta de propriedade, propriedade mutável reatribuída)
Use reflexão:
Com suas próprias ferramentas de reflexão ou com um auxiliar externo (como jakarta common-beans), é fácil escrever um método genérico de cópia que fará o trabalho em uma linha.
pro:
- fácil de escrever
- sem
contras de manutenção :
- menos controle do que acontece
- propenso a erros com objetos mutáveis se a ferramenta de reflexão também não clonar sub-objetos
- execução mais lenta
Use a estrutura do clone:
Use uma estrutura que faça isso por você, como:
commons-lang SerializationUtils
Java Deep Cloning Library
Dozer
Kryo
pro:
- o mesmo que reflexão
- mais controle sobre o que será exatamente clonado.
contras:
- toda instância mutável é totalmente clonada, mesmo no final da hierarquia
- pode ser muito lenta para executar
Use a instrumentação bytecode para gravar clone em tempo de execução
javassit , BCEL ou cglib podem ser usados para gerar um clonador dedicado tão rápido quanto uma mão escreveu. Alguém conhece uma biblioteca usando uma dessas ferramentas para esse fim?
O que eu perdi aqui?
Qual desses você recomendaria ?
Obrigado.
Respostas:
Para clonagem profunda (clona toda a hierarquia de objetos):
commons-lang SerializationUtils - usando serialização - se todas as classes estiverem sob seu controle e você puder forçar a implementação
Serializable
.Biblioteca Java Deep Cloning - usando reflexão - nos casos em que as classes ou os objetos que você deseja clonar estão fora de seu controle (uma biblioteca de terceiros) e você não pode implementá-los
Serializable
, ou nos casos em que não deseja implementarSerializable
.Para clonagem superficial (clona apenas as propriedades de primeiro nível):
commons-beanutils BeanUtils - na maioria dos casos.
Spring BeanUtils - se você já estiver usando spring e, portanto, tenha esse utilitário no caminho de classe.
Omiti deliberadamente a opção "faça você mesmo" - as APIs acima fornecem um bom controle sobre o que fazer e o que não clonar (por exemplo
transient
, usando ouString[] ignoreProperties
), portanto, não é preferível reinventar a roda.fonte
O livro de Joshua Bloch tem um capítulo inteiro intitulado "Item 10: Substituir judiciosamente o clone", no qual ele explica por que substituir o clone geralmente é uma má idéia, porque a especificação Java para ele cria muitos problemas.
Ele fornece algumas alternativas:
Use um padrão de fábrica no lugar de um construtor:
Use um construtor de cópia:
Todas as classes de coleção em Java suportam o construtor de cópias (por exemplo, novo ArrayList (l);)
fonte
Copyable
interface que contém umgetCopy()
método. Basta usar o padrão de protótipo manualmente.newInstance()
método e oYum
construtor faria uma cópia profunda ou superficial?Desde a versão 2.07, o Kryo suporta clonagem superficial / profunda :
O Kryo é rápido, na e na página deles você pode encontrar uma lista de empresas que o utilizam na produção.
fonte
Use XStream toXML / fromXML na memória. Extremamente rápido e existe há muito tempo e está forte. Os objetos não precisam ser serializáveis e você não precisa usar reflexão (embora o XStream o faça). O XStream pode discernir variáveis que apontam para o mesmo objeto e não acidentalmente fazem duas cópias completas da instância. Muitos detalhes como esse foram detalhados ao longo dos anos. Eu o uso há vários anos e é uma opção. É tão fácil de usar quanto você pode imaginar.
ou
Clonar,
Mais sucintamente:
fonte
Para objetos complicados e quando o desempenho não é significativo, uso o gson para serializar o objeto para o texto json e, em seguida, desserialize o texto para obter um novo objeto.
O gson, que com base na reflexão, funciona na maioria dos casos, exceto que os
transient
campos não serão copiados e os objetos com referência circular com causaStackOverflowError
.fonte
Depende.
Para velocidade, use DIY. Para à prova de balas, use reflexão.
BTW, serialização não é a mesma que refl, pois alguns objetos podem fornecer métodos de serialização substituídos (readObject / writeObject) e podem ser com erros
fonte
Eu recomendaria a maneira DIY que, combinada com um bom método hashCode () e equals (), deve ser fácil de ser testada em um teste de unidade.
fonte
Eu sugiro que substitua Object.clone (), chame super.clone () primeiro e depois chame ref = ref.clone () em todas as referências que você deseja copiar profundamente. É mais ou menos a abordagem Faça você mesmo , mas precisa de um pouco menos de codificação.
fonte
Para clonagem profunda, implemente Serializable em todas as classes que você deseja clonar assim
E então use esta função:
como isso:
Obj newObject = (Obj)deepClone(oldObject);
fonte