Como faço para copiar um object em Java?

Considere o código abaixo:

DummyBean dum = new DummyBean(); dum.setDummy("foo"); System.out.println(dum.getDummy()); // prints 'foo' DummyBean dumtwo = dum; System.out.println(dumtwo.getDummy()); // prints 'foo' dum.setDummy("bar"); System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo' 

Por isso, quero copiar o dum para o dumtwo e mudar o dum sem afectar o dumtwo . Mas o código acima não está fazendo isso. Quando eu mudo algo em dum , a mesma mudança está acontecendo em dumtwo também.

Eu acho que, quando digo dumtwo = dum , Java copia apenas a referência . Então, existe alguma maneira de criar uma nova cópia do dum e atribuí-lo ao dumtwo ?

Crie um construtor de cópia:

 class DummyBean { private String dummy; public DummyBean(DummyBean another) { this.dummy = another.dummy; // you can access } } 

Todo object tem também um método clone que pode ser usado para copiar o object, mas não o use. É muito fácil criar uma class e fazer um método clone inadequado. Se você vai fazer isso, leia pelo menos o que Joshua Bloch tem a dizer sobre isso em Java eficaz .

Básico: Cópia de Objetos em Java.

Vamos supor que um object- obj1 , que contém dois objects, contenhaObj1 e contenhaObj2 .
insira a descrição da imagem aqui

cópia superficial:
cópia superficial cria uma nova instance da mesma class e copia todos os campos para a nova instância e a retorna. A class de object fornece um método clone e fornece suporte para a cópia superficial.
insira a descrição da imagem aqui

Cópia profunda:
Uma cópia profunda ocorre quando um object é copiado junto com os objects aos quais ele se refere . A imagem abaixo mostra obj1 depois que uma cópia profunda foi executada nela. Não apenas obj1 foi copiado , mas os objects contidos nele também foram copiados. Podemos usar a Java Object Serialization para fazer uma cópia profunda. Infelizmente, essa abordagem também apresenta alguns problemas ( exemplos detalhados ).
insira a descrição da imagem aqui

Possíveis problemas:
clone é complicado de implementar corretamente.
É melhor usar os methods de cópia defensiva , copiar construtores (como @egaga reply) ou estático .

  1. Se você tem um object, que você sabe que tem um método clone() público clone() , mas você não sabe o tipo do object em tempo de compilation, então você tem problema. Java tem uma interface chamada Cloneable . Na prática, devemos implementar essa interface se quisermos tornar um object Cloneable . Object.clone é protegido , portanto, devemos substituí- lo por um método público para que seja acessível.
  2. Outro problema surge quando tentamos copiar em profundidade um object complexo . Suponha que o método clone() de todas as variables ​​de object membro também faça cópia profunda, isso é muito arriscado de uma suposição. Você deve controlar o código em todas as classs.

Por exemplo, org.apache.commons.lang.SerializationUtils terá o método para clone Deep usando serialização ( Source ). Se precisarmos clonar o Bean, existem alguns methods utilitários em org.apache.commons.beanutils ( Source ).

  • cloneBean irá clonar um bean com base nos getters e setters de propriedades disponíveis, mesmo se a class do bean não implementar Cloneable.
  • copyProperties valores de propriedade do bean de origem para o bean de destino em todos os casos em que os nomes das propriedades forem iguais.

Apenas siga como abaixo:

 public class Deletable implements Cloneable{ private String str; public Deletable(){ } public void setStr(String str){ this.str = str; } public void display(){ System.out.println("The String is "+str); } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } 

e onde quer que você queira obter outro object, basta executar a clonagem. por exemplo:

 Deletable del = new Deletable(); Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent // object, the changes made to this object will // not be reflected to other object 

No pacote import org.apache.commons.lang.SerializationUtils; existe um método:

 SerializationUtils.clone(Object); 

Exemplo:

 this.myObjectCloned = SerializationUtils.clone(this.object); 

Por que não há resposta para o uso da Reflection API?

 private static Object cloneObject(Object obj){ try{ Object clone = obj.getClass().newInstance(); for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); field.set(clone, field.get(obj)); } return clone; }catch(Exception e){ return null; } } 

É muito simples.

EDIT: include object filho por meio de recursion

 private static Object cloneObject(Object obj){ try{ Object clone = obj.getClass().newInstance(); for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){ continue; } if(field.getType().isPrimitive() || field.getType().equals(String.class) || field.getType().getSuperclass().equals(Number.class) || field.getType().equals(Boolean.class)){ field.set(clone, field.get(obj)); }else{ Object childObj = field.get(obj); if(childObj == obj){ field.set(clone, clone); }else{ field.set(clone, cloneObject(field.get(obj))); } } } return clone; }catch(Exception e){ return null; } } 

Eu uso biblioteca JSON do Google para serializá-lo, em seguida, criar uma nova instância do object serializado. Faz cópia em profundidade com algumas restrições:

  • não pode haver referências recursivas

  • não copiará matrizes de tipos diferentes

  • matrizes e listas devem ser digitadas ou não encontrará a class para instanciar

  • você pode precisar encapsular strings em uma class que você se declara

Eu também uso essa class para salvar as preferências do usuário, janelas e outras coisas a serem recarregadas em tempo de execução. É muito fácil de usar e eficaz.

 import com.google.gson.*; public class SerialUtils { //___________________________________________________________________________________ public static String serializeObject(Object o) { Gson gson = new Gson(); String serializedObject = gson.toJson(o); return serializedObject; } //___________________________________________________________________________________ public static Object unserializeObject(String s, Object o){ Gson gson = new Gson(); Object object = gson.fromJson(s, o.getClass()); return object; } //___________________________________________________________________________________ public static Object cloneObject(Object o){ String s = serializeObject(o); Object object = unserializeObject(s,o); return object; } } 

Sim, você está apenas fazendo uma referência ao object. Você pode clonar o object se ele implementar Cloneable .

Confira este artigo wiki sobre como copiar objects.

Consulte aqui: Cópia de object

Sim. Você precisa copiar profundamente seu object.

Adicionar Cloneable e código abaixo à sua turma

 public Object clone() throws CloneNotSupportedException { return super.clone(); } 

Use este clonedObject = (YourClass) yourClassObject.clone();

Aqui está uma explicação decente do clone() se você acabar precisando dele …

Aqui: clone (método Java)

Isso também funciona. Assumindo o modelo

 class UserAccount{ public int id; public String name; } 

Primeiro, adicione compile 'com.google.code.gson:gson:2.8.1' ao seu aplicativo> gradle & sync. Então

 Gson gson = new Gson(); updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class); 

Você pode excluir usando um campo usando a palavra-chave transient após o modificador de access.

Nota: Esta é uma prática ruim. Também não recomendo usar Cloneable ou JavaSerialization É lento e quebrado. Escreva construtor de cópia para melhor desempenho ref .

Algo como

 class UserAccount{ public int id; public String name; //empty constructor public UserAccount(){} //parameterize constructor public UserAccount(int id, String name) { this.id = id; this.name = name; } //copy constructor public UserAccount(UserAccount in){ this(in.id,in.name); } } 

Estatísticas de teste da iteração 90000:
Linha UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); leva 808ms

Linha UserAccount clone = new UserAccount(aO); leva menos de 1ms

Conclusão: Use gson se o seu chefe é louco e você prefere velocidade. Use o segundo construtor de cópia se você preferir qualidade.

Você também pode usar o plugin do gerador de código de construtor de cópia no Android Studio.

Para fazer isso, você precisa clonar o object de alguma forma. Embora o Java tenha um mecanismo de clonagem, não o use se não for necessário. Crie um método de cópia que faça o trabalho de cópia para você e faça:

 dumtwo = dum.copy(); 

Aqui estão mais alguns conselhos sobre diferentes técnicas para realizar uma cópia.

Deep Cloning é sua resposta, que requer a implementação da interface Cloneable e a substituição do método clone() .

 public class DummyBean implements Cloneable { private String dummy; public void setDummy(String dummy) { this.dummy = dummy; } public String getDummy() { return dummy; } @Override public Object clone() throws CloneNotSupportedException { DummyBean cloned = (DummyBean)super.clone(); cloned.setDummy(cloned.getDummy()); // the above is applicable in case of primitive member types, // however, in case of non primitive types // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone()); return cloned; } } 

Você vai chamá-lo assim DummyBean dumtwo = dum.clone();

Use um utilitário de clonagem profunda:

 SomeObjectType copy = new Cloner().deepClone(someObject); 

Isto irá copiar profundamente qualquer object java, confira em https://github.com/kostaskougios/cloning

Além de copiar explicitamente, outra abordagem é tornar o object imutável (nenhum set ou outro método mutador). Desta forma, a questão nunca surge. A imutabilidade se torna mais difícil com objects maiores, mas o outro lado disso é que ela o empurra na direção de se dividir em pequenos objects e compostos coerentes.

 class DB { private String dummy; public DB(DB one) { this.dummy = one.dummy; } } 

Passe o object que você quer copiar e pegue o object que você quer,

 private Object copyObject(Object objSource) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(objSource); oos.flush(); oos.close(); bos.close(); byte[] byteData = bos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(byteData); try { objDest = new ObjectInputStream(bais).readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } return objDest; } 

Agora, analise o objDest para o object desigerado.

Codificação Feliz

Você pode tentar implementar Cloneable e usar o método clone() ; no entanto, se você usar o método clone, deverá – por padrão – replace SEMPRE o método public Object clone() .

Você pode copiar em profundidade automaticamente com o XStream, em http://x-stream.github.io/ :

XStream é uma biblioteca simples para serializar objects para XML e vice-versa.

Adicione ao seu projeto (se estiver usando maven)

  com.thoughtworks.xstream xstream 1.3.1  

Então

 DummyBean dum = new DummyBean(); dum.setDummy("foo"); DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum)); 

Com isso, você tem uma cópia sem a necessidade de implementar qualquer interface de clonagem.

Se você puder adicionar uma anotação ao arquivo de origem, um processador de anotação ou gerador de código como este pode ser usado.

 import net.zerobuilder.BeanBuilder @BeanBuilder public class DummyBean { // bean stuff } 

Uma class DummyBeanBuilders será gerada, que possui um método estático dummyBeanUpdater para criar cópias rasas, da mesma forma que você faria manualmente.

 DummyBean bean = new DummyBean(); // Call some setters ... // Now make a copy DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done(); 
 public class MyClass implements Cloneable { private boolean myField= false; // and other fields or objects public MyClass (){} @Override public MyClass clone() throws CloneNotSupportedException { try { MyClass clonedMyClass = (MyClass)super.clone(); // if you have custom object, then you need create a new one in here return clonedMyClass ; } catch (CloneNotSupportedException e) { e.printStackTrace(); return new MyClass(); } } } 

e no seu código:

 MyClass myClass = new MyClass(); // do some work with this object MyClass clonedMyClass = myClass.clone();