Este artigo discutirá as 4 edições a seguir
1. Interface clonável Java implementa cópias profundas
2. A serialização de java implementa cópias profundas
3. A Análise de Código Fonte de Clonagem da Biblioteca Binária mais rápida de cópia profunda
4. Comparação de velocidades de vários métodos de cópia
Não vou falar sobre o conceito de cópia profunda neste artigo. Implementando cópia profunda em C ++. Geralmente, sobrecarregar o operador de atribuição "=" para implementar cópias profundas entre objetos da mesma classe. Portanto, é natural que, em Java, também possamos definir uma função de cópia para atribuir cada propriedade do objeto dentro da função. Esse método é simples e natural, mas há um problema fatal: se um dia um novo atributo que requer cópia profunda é adicionada à classe, a função de cópia correspondente também deve ser modificada. Este método traz grande inconveniência à extensibilidade da classe. Como resolver esse problema, vejamos o método de implementação dos capítulos 1, 2 e 3 e o teste de velocidade da Seção 4.
1. A interface clonável Java implementa cópias profundas <r /> dessa maneira, a classe precisa implementar a função de clone de interface colnível e chamar Super.clone na função clone. Esta cópia profunda do método também traz outro problema. Se houver objetos de outras classes como propriedades da classe, outras classes também precisam ser sobrecarregadas e implementadas na interface clonável. Aqui está um exemplo. No exemplo a seguir, o Complexdo contém objetos SimpleDo. Para implementar a cópia do Complexdo Deep, você precisa primeiro implementar a interface clone da Simpleedo:
A classe pública Simpledo implementa clonável, serializável {private int x = 1; String privada S = "SimpleDo"; @Override Protected Object clone () lança clonenotsupportedException {SimpleDo newclass = (simpledo) super.clone (); retornar newclass; }} classe pública Complexdo implementa clonável, serializável {private int x = 1; String privada S = "Complex"; Inteiro privado a = 123; Inteiro privado b = 1234; Inteiro privado c = 1334455; String privada S2 = "hehehe"; String privada S3 = "hahaha"; Private Long Id = 1233245L; Private ArrayList <Simpledo> l = new ArrayList <Alededo> (); @Override public Object clone () lança clonenotsupportedException {complexdo newclass = (complexdo) super.clone (); newclass.l = new ArrayList <AledoDo> (); for (simplificado simples: this.l) {newclass.l.add ((simpledo) simples.clone ()); } retornar newclass; }} Deve -se notar que muitos artigos dizem que o operador de atribuição do tipo de string é uma cópia profunda, mas, de fato, aqueles que usam operadores de atribuição em Java são cópias rasas, mas por que artigos com erros tão óbvios precisam dizer que essa é uma cópia profunda? Meu entendimento é que os atributos de string e tipo são tipos básicos, e o método fornecido será novos objetos, desde que as alterações de dados internas sejam projetadas. Portanto, uma operação de string não afetará a memória que apontou originalmente. Portanto, de um modo geral, as operações de atribuição de classes básicas, como string, são cópias profundas.
Por esse motivo, ao usar o splicing de sequência de string, a nova memória precisa ser aberta, muitas pessoas recomendam o uso do StringBuilder em vez de String para splicing, porque o StringBuilder apenas reaplica a memória maior quando a faixa de matriz de char embutida não for suficiente (para JVMs modernos, o código será ajustado e a string será otimizada em instruções semelhantes para stringbilder.append). Para cortar opostos ao splicing, há uma função de substring na string. Ao usar a função de substring, a matriz de char interna da nova string é a mesma que a string original? Isso é mais interessante. Se você estiver interessado, pode comparar e verificar a implementação de JDK1.6 e JKD1.7.
2. A serialização de java implementa cópias profundas
O princípio deste método é usar a serialização do Java para serializar um objeto em um fluxo de bytes binários e, em seguida, desaperializar e atribuir o valor a um objeto. Exemplo de código:
Public Object Seircopy (Object src) {try {byteArrayOutputStream byteout = new ByteArrayOutputStream (); ObjectOutputStream Out = new ObjectOutputStream (byteout); out.WriteObject (SRC); ByteArrayInputStream bytein = new byteArrayInputStream (byteout.tobytearray ()); ObjectInputStream in = new ObjectInputStream (bytein); Objeto dest = in.readObject (); retorno dest; } catch (Exceção e) {// Faça algum manipulador de erros retornar null; }} Obviamente, você também pode usar o JSON e outras bibliotecas serializadas para concluir a serialização. Esse método evita efetivamente as deficiências extensíveis da interface clonabel. Uma função pode basicamente ser adequada para todas as classes. A desvantagem é que é uma cópia relativa da memória. A serialização requer primeiro a conversão do objeto em um fluxo de bytes binários e depois desaperializando novamente o fluxo de bytes binários em uma peça de memória do objeto, que é relativamente lenta.
3. A Análise de Código Fonte de Clonagem da Biblioteca Binária mais rápida de cópia profunda
No código -fonte, a lógica de processamento principal está na classe Cloner.
Existem dois links recursivos:
Em (1), o FastClone completa objetos herdados da classe IFASTCLONE Interface, ou seja, são todas cópias das operações de coleta;
Em (2), o CloneObject conclui o processo de obtenção de cada propriedade do objeto normal através do mecanismo de reflexão e, em seguida, atribuindo valores às propriedades do objeto recém -gerado usando objesese.
Este método é altamente extensível. Você não apenas pode confiar no código existente para concluir a cópia profunda, mas também pode definir alguns métodos e tipos de clonagem que não requerem clonagem, o que é altamente flexível.
4. Comparação de velocidades de vários métodos de cópia
Os três modos acima podem ser usados para concluir a cópia profunda, e o método de cópia mais rápido é o que nos preocupamos.
Primeiro, teste o código:
public void testClOneComplex () lança clonenotsupportedException {final int copycount = 1; List <CuxlexDO> complexDolist = new ArrayList <CuxexDDO> (copycount * 3); complexo final complexo = new Complexdo (); // calculando a biblioteca de dois lados long start = system.currenttimemillis (); for (int i = 0; i <copycount; ++ i) {Final Complexdo DeepClone = Clner.DeepClone (Complexo); complexDolist.add (DeepClone); } long end = System.currenttimemillis (); System.out.println ("DeepClone Cost Time =" + (End-Start)); // chamando a função clone implementada pela interface clonável start = system.currenttimemillis (); for (int i = 0; i <copycount; ++ i) {Final Complexdo interfaceclone = (complexDo) complex.clone (); complexDolist.add (interfaceclone); } end = System.currenttimemillis (); System.out.println ("interfaceclone Cost Time =" + (End-Start)); // serialização e desserialização geram novo objeto start = system.currenttimemillis (); for (int i = 0; i <copycount; ++ i) {Final Complexdo Seirclone = Seircopy (complexo); complexDolist.add (Seirclone); } end = System.currenttimemillis (); System.out.println ("Seirclone Cost Time =" + (start final)); }A unidade de resultados de execução são milissegundos (esses dados são ignorados e não calcula pontos de acesso Java e possíveis GCs).
Nesta tabela, podemos tirar a conclusão:
1. A cópia da interface clonável é a mais rápida, porque envolve apenas cópias de memória, mas se os atributos envolvidos forem objetos mais comuns, é um pouco problemático escrever.
2. A cópia de serialização/deserialização é a mais lenta
3. Usando a biblioteca de clonagem, a cópia do mecanismo de recursão e reflexão é mais lenta que a implementação da interface clonável, mas mais rápida que o método de serialização.
O exposto acima é tudo sobre este artigo, espero que seja útil para o aprendizado de todos.