Prefácio
A clonagem de Java (clone) é uma das características da língua Java, mas é raro usá -lo na prática. Mas às vezes a clonagem é mais conveniente e eficiente.
Para clones, Java tem algumas limitações:
1. A classe clonada deve implementar a própria interface clonável para indicar que Object.clone() pode copiar legalmente a instância desta classe por campo. A interface clonável é na verdade uma interface de identificação e não possui um método de interface.
2. As classes que implementam a interface clonável devem substituir Object.clone (está protegido) usando métodos públicos. É impossível para um objeto cloná -lo após a implementação dessa interface. Mesmo que o método clone seja chamado de reflexivamente, não há garantia de que ele terá sucesso.
3. O método de clonagem na classe Java.lang.Object é definido da seguinte forma:
Objeto protegido clone () lança clonenotsupportedException
Cria e retorna uma cópia deste objeto. Indica que é um método protegido, visível no mesmo pacote.
Por convenção, o objeto retornado deve ser obtido chamando super.clone .
Tarefa em java
Em Java, a tarefa é muito comumente usada, uma tarefa simples é a seguinte
// o tipo original int a = 1; int b = a; // tipo de referência string [] weekdays = new string [5]; string [] gongzuori = weekdays; // cópia apenas referências
No código acima.
1. Se for o tipo de dados original, o valor passado pela atribuição é o valor real.
2. Se for um tipo de dados de referência, a atribuição passa a referência ao objeto, não ao objeto.
A compreensão da diferença entre os tipos de dados e os tipos de referência facilita a compreensão do clone.
Clone
Em Java, o clone é o processo de copiar um objeto existente na memória para outro objeto que é o mesmo que ele. A clonagem em Java é uma cópia de domínio por domínio.
Se você deseja apoiar métodos de clone em Java, você precisa primeiro implementar a interface clonável
CLONEED é realmente um pouco estranho. É diferente da interface que costumamos usar. Ele não contém nenhum método dentro, é apenas uma interface de marcação.
O código -fonte é o seguinte
interface pública clonável {}Sobre clonável, o que deve receber atenção
1. Se você deseja apoiar o clone, precisa implementar a interface clonável
2. Se o método do clone não for chamado para a interface clonável, será lançada uma clonenotsupportedException.
Em seguida, reescreva o método do clone e modifique -o no nível de acesso público
classe estática cloneableimp implementa clonável {public int conting; criança pública; @Override public Object clone () lança clonenotsupportedException {return super.clone (); }}Chamada Método do clone para copiar o objeto
CloneableImp Imp1 = new CLONEABLIMP (); imp1.CHILD = new Child ("Andy"); tente {objeto obj = imp1.clone (); CloneableImp Imp2 = (cloneableImp) obj; System.out.println ("Main Imp2.Child.Name =" + Imp2.Child.Name);} Catch (CLONENOTSupportEdException e) {E.printStackTrace ();}Cópia leve
O clone implementado no código acima é na verdade uma cópia rasa.
O que você deve saber sobre cópia superficial
1. Use o método de clone padrão
2. Faça uma cópia de valor do campo de dados original
3. Somente cópia referências para tipos de referência
4. Execução rápida e alta eficiência
5. Os dados não podem ser separados em 100%.
6. Se um objeto contiver apenas o domínio de dados original ou o domínio de objeto imutável, é recomendável usar cópia superficial.
Em relação à incapacidade de separar dados, podemos usar esse código para verificar.
CloneableImp Imp1 = new CLONEABLIMP (); imp1.CHILD = new Child ("Andy"); tente {objeto obj = imp1.clone (); CloneableImp Imp2 = (cloneableImp) obj; imp2.child.name = "bob"; System.out.println ("Main Imp1.Child.Name =" + Imp1.Child.Name);} Catch (CLONOTSupportEdException e) {E.printStackTrace ();} No código acima, usamos o método clone do IMP1 para clonar o IMP2, depois modificado imp2.child.name para Bob e, em seguida, imprimimos imp1.child.name para obter o resultado.
principal imp1.child.name = bob
O motivo é que a cópia rasa não atinge 100% de separação dos dados. IMP1 e IMP2 compartilham o mesmo objeto infantil, portanto, uma modificação afetará a outra.
Cópia profunda
A cópia profunda pode resolver o problema de 100% de separação de dados. Basta fazer algumas modificações no código acima.
1. A criança implementa a interface clonável.
classe pública Child implementa clonável {name public string; public filho (nome da string) {this.name = name; } @Override public string tostring () {return "Child [name =" + name + "]"; } @Override Protected Object clone () lança CLONENOTSupportEdException {return super.clone (); }}2. Reescreva o método do clone e chame o método clone do domínio de dados.
classe estática cloneableimp implementa clonável {public int conting; criança pública; @Override public Object clone () lança clonenotsupportedException {cloneableImp obj = (cloneableImp) super.clone (); obj.child = (filho) filho.clone (); retornar obj; }} Quando modificamos imp2.child.name novamente, ele não afetará o valor do imp1.child.name , porque o IMP1 e o IMP2 têm seus próprios objetos infantis, porque os dados são 100% isolados.
Algumas características de cópia profunda
1. Você precisa substituir o método do clone, não apenas chamando o método da classe pai, mas também chamando o método clone do atributo.
2. 100% de separação de dados entre o objeto original e o objeto clonado é alcançado
3. Se o objeto tiver um atributo de tipo de referência, é recomendável usar cópia profunda.
4. A cópia profunda é mais demorada e menos eficiente que a cópia rasa
Por que usar clonagem
É muito importante e comum: uma API precisa fornecer uma coleção de listas, mas não deseja que a modificação do chamador afete suas próprias alterações, por isso precisa clonar um objeto para alcançar o objetivo do isolamento de dados.
Cloone deve ser evitado o máximo possível
1. Geralmente, a interface é implementada para mostrar o que a classe pode fazer por seus clientes, enquanto o clonável é apenas uma interface de tags e também altera o comportamento do método protegido à mão na superclasse. É um uso extremamente atípico da interface e não é digno de imitação.
2. A descrição Javadoc da Convenção do Método do Clone e seu frágil método de clone é um pouco ambíguo, como segue: a Convenção Java SE8
O método clone cria e retorna uma cópia do objeto. O significado exato da cópia depende da classe do objeto. O significado geral é que, para qualquer objeto x, a expressão
x.clone() != x 为true x.clone().getClass() == x.getClass() também retorna true, mas não necessário x.clone().equals(x) também retorna verdadeiro, mas não necessário, mas não necessário
A segunda e a terceira expressões acima retornam facilmente falsas. Portanto, a única coisa que pode garantir a verdade permanente é a expressão um, ou seja, os dois objetos são objetos independentes.
3. O domínio final do objeto variável. No método de clonagem, se precisarmos copiar o domínio final do objeto variável, é realmente impossível compilar e passar devido a restrições finais. Portanto, para implementar a clonagem, precisamos considerar o abandono da palavra -chave final do domínio do objeto mutável.
4. Segurança do thread Se você decidir usar classes seguras de threads para implementar a interface clonável, é necessário garantir que seu método de clone seja sincronizado. O método Object.clone padrão não é sincronizado.
Em geral, o método clone em Java não é realmente perfeito, por isso é recomendável evitar usá -lo o máximo possível. Aqui estão algumas alternativas.
Copiar construtores
Os objetos de cópia também podem ser implementados usando um construtor de cópias.
1. Construtor de cópia também é um tipo de construtor
2. Apenas um parâmetro é aceito, o tipo de parâmetro é a classe atual
3. O objetivo é gerar um novo objeto com os mesmos parâmetros que
4. A vantagem do método do Clone Over Clone é que ele é simples e fácil de implementar.
Um código de exemplo usando um construtor de cópia
Public Class Car {roda da roda; Fabricante de string; Public Car (roda, fabricante de cordas) {this.wheel = roda; this.Manufacturer = fabricante; } // copiar o construtor público (carro) {this (car.wheel, car.Manufacturer); } classe estática pública roda {marca de string; }}Observe que o código acima é implementado como uma cópia rasa. Se você deseja implementar uma cópia profunda, consulte o código a seguir.
// copiar o constructorpublic car (carro) {roda da roda = new Wheel (); wheel.brand = car.wheel.brand; this.wheel = roda; this.Manufacturer = Car.Manufacturer;}Para mais conveniência, também podemos adicionar um método estático à classe acima
Public Static Car NewInstance (carro do carro) {Return New Car (carro);}Use serializável para obter uma cópia profunda
De fato, a cópia profunda dos objetos pode ser alcançada usando a serialização. O breve código é o seguinte
classe pública DeepcopyExample implementa serializável {private estático final serialversionuid = 6098694917984051357L; criança pública; public DeepCopyExample Copy () {DeepCopyExample Copy = null; tente {bytearrayoutputStream baos = novo byteArrayOutputStream (); ObjectOutputStream ooS = new ObjectOutputStream (BAOS); OOS.WriteObject (this); ByteArrayInputStream Bais = new ByteArrayInputStream (baos.tobytearray ()); ObjectInputStream ois = new ObjectInputStream (Bais); cópia = (DeepCopyExample) OIS.readObject (); } catch (ioexception e) {e.printStackTrace (); } catch (classNotFoundException e) {e.printStackTrace (); } Retornar cópia; }}Entre eles, a criança deve implementar a interface serializável
classe pública implementa a criança serializável {private estático final serialversionuid = 6832122780722711261L; public string name = ""; public filho (nome da string) {this.name = name; } @Override public string tostring () {return "Child [name =" + name + "]"; }}Use exemplos e código de teste
Exemplo DeepCopyExample = new DeepCopyExample (); exemplo.Child = New Child ("Exemplo"); DeepCopyExample cópia = exemplo.copy (); if (copy! = null) {copy.child.name = "copiado"; System.out.println ("Explet.Child =" + Exemplo.CHILD + "; COPY.CHILD =" + COPY.CHILD);} // Resultado da saída: Exemplo.Child = Child [Nome = Exemplo]; Copy.Child = Child [Nome = Copiado]A julgar pelos resultados da saída, modificar o valor da criança do objeto de cópia não afeta o valor da criança do objeto Exemplo, ou seja, usando a serialização para obter uma cópia profunda do objeto.
Resumir
O exposto acima é todo o conteúdo da clonagem em Java. Espero que este artigo seja útil para que todos aprendam Java.