Come posso copiare un object in Java?

Considera il codice qui sotto:

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' 

Quindi, voglio copiare il dum in dumtwo e cambiare dum senza influenzare il dumtwo . Ma il codice sopra non lo sta facendo. Quando cambio qualcosa in dum , lo stesso cambiamento avviene anche in dumtwo .

Suppongo che, quando dico dumtwo = dum , Java copi solo il riferimento . Quindi, c’è un modo per creare una nuova copia di dum e assegnarla a dumtwo ?

Creare un costruttore di copie:

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

Ogni object ha anche un metodo clone che può essere usato per copiare l’object, ma non usarlo. È troppo semplice creare una class e fare un metodo di clonazione improprio. Se hai intenzione di farlo, leggi almeno quello che Joshua Bloch ha da dire a riguardo in Effective Java .

Di base: copia di oggetti in Java.

Assumiamo un object- obj1 , che contiene due oggetti, contenutoObj1 e contenutoObj2 .
inserisci la descrizione dell'immagine qui

copiatura superficiale:
la copia superficiale crea una nuova instance della stessa class e copia tutti i campi nella nuova istanza e la restituisce. La class Object fornisce un metodo clone e fornisce il supporto per la copia superficiale.
inserisci la descrizione dell'immagine qui

Copia profonda:
Una copia profonda si verifica quando un object viene copiato insieme agli oggetti a cui fa riferimento . L’immagine sotto mostra obj1 dopo che è stata eseguita una copia profonda su di essa. Non solo è stato copiato obj1 , ma anche gli oggetti contenuti al suo interno sono stati copiati. Possiamo usare la Java Object Serialization per fare una copia profonda. Sfortunatamente, questo approccio ha anche alcuni problemi ( esempi dettagliati ).
inserisci la descrizione dell'immagine qui

Possibili problemi:
clone è difficile da implementare correttamente.
È meglio usare la copia difensiva , i costruttori di copia (come risposta @egaga) oi metodi di fabbrica statici .

  1. Se hai un object, che conosci un metodo clone() pubblico, ma non conosci il tipo di object in fase di compilazione, allora hai un problema. Java ha un’interfaccia chiamata Cloneable . In pratica, dovremmo implementare questa interfaccia se vogliamo creare un object Cloneable . Object.clone è protetto , quindi è necessario sostituirlo con un metodo pubblico per renderlo accessibile.
  2. Un altro problema sorge quando proviamo la copia profonda di un object complesso . Supponiamo che anche il metodo clone() di tutte le variabili object membro faccia una copia profonda, questo è troppo rischioso per un’ipotesi. È necessario controllare il codice in tutte le classi.

Ad esempio, org.apache.commons.lang.SerializationUtils disporrà del metodo per Deep clone utilizzando la serializzazione ( Source ). Se abbiamo bisogno di clonare Bean, ci sono un paio di metodi di utilità in org.apache.commons.beanutils ( Source ).

  • cloneBean un bean basato sui getter e setter della proprietà disponibili, anche se la class bean non implementa Cloneable.
  • copyProperties copia i valori delle proprietà dal bean di origine al bean di destinazione per tutti i casi in cui i nomi delle proprietà sono gli stessi.

Basta seguire come di seguito:

 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 ovunque tu voglia ottenere un altro object, esegui semplicemente la clonazione. per esempio:

 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 

Nel pacchetto import org.apache.commons.lang.SerializationUtils; c’è un metodo:

 SerializationUtils.clone(Object); 

Esempio:

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

Perché non c’è una risposta per l’utilizzo dell’API di Reflection?

 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; } } 

È davvero semplice

EDIT: Include object figlio tramite ricorsione

 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; } } 

Uso la libreria JSON di Google per serializzarlo, quindi creare una nuova istanza dell’object serializzato. Copia in profondità con alcune restrizioni:

  • non ci possono essere riferimenti ricorsivi

  • non copierà le matrici di tipi disparati

  • array e liste dovrebbero essere digitati o non troverà la class da istanziare

  • potrebbe essere necessario incapsulare le stringhe in una class dichiarata dall’utente

Uso anche questa class per salvare le preferenze utente, windows e quant’altro da ricaricare in fase di runtime. È molto facile da usare ed efficace.

 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; } } 

Sì, stai solo facendo riferimento all’object. È ansible clonare l’object se implementa Cloneable .

Dai un’occhiata a questo articolo della wiki su come copiare oggetti.

Fare riferimento qui: Copia di oggetti

Sì. Devi copiare in profondità il tuo object.

Aggiungi Cloneable e sotto codice alla tua class

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

Usa questo clonedObject = (YourClass) yourClassObject.clone();

Ecco una spiegazione decente di clone() se finisci per averne bisogno …

Qui: clone (metodo Java)

Anche questo funziona. Supponendo modello

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

Innanzitutto aggiungi compile 'com.google.code.gson:gson:2.8.1' alla tua app> gradle & sync. Poi

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

È ansible escludere l’utilizzo di un campo utilizzando la parola chiave transient dopo il modificatore di accesso.

Nota: questa è una ctriggers pratica. Inoltre, non è consigliabile utilizzare JavaSerialization o JavaSerialization È lento e danneggiato. Scrivi costruttore di copia per il miglior rendimento ref .

Qualcosa di simile a

 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); } } 

Statistiche di prova di 90000 iterazione:
Line UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); prende 808 ms

Line UserAccount clone = new UserAccount(aO); richiede meno di 1 ms

Conclusione: usa il gson se il tuo capo è pazzo e preferisci la velocità. Utilizzare il costruttore di seconda copia se si preferisce la qualità.

Puoi anche utilizzare il plug- in del generatore di codice del costruttore di copia in Android Studio.

Per farlo devi clonare l’object in qualche modo. Sebbene Java abbia un meccanismo di clonazione, non usarlo se non è necessario. Crea un metodo di copia che faccia funzionare la copia per te, quindi esegui:

 dumtwo = dum.copy(); 

Ecco qualche altro consiglio su diverse tecniche per realizzare una copia.

Deep Cloning è la tua risposta, che richiede l’implementazione dell’interfaccia Cloneable e l’override del metodo 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; } } 

Lo chiamerai come questo DummyBean dumtwo = dum.clone();

Utilizzare un’utilità di clonazione profonda:

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

Questo copierà in profondità qualsiasi object java, verificarlo su https://github.com/kostaskougios/cloning

Oltre a copiare esplicitamente, un altro approccio è rendere l’object immutabile (nessun set o altri metodi di mutatore). In questo modo la domanda non si pone mai. L’immutabilità diventa più difficile con oggetti più grandi, ma l’altro lato è che ti spinge nella direzione della divisione in oggetti e compositi coerenti.

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

Passa l’object che vuoi copiare e prendi l’object che vuoi,

 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; } 

Ora analizza l’object objDest in object desigerato.

Felice codifica

Puoi provare a implementare Cloneable e usare il metodo clone() ; tuttavia, se si utilizza il metodo clone, è necessario – per impostazione predefinita – sovrascrivere SEMPRE il metodo public Object clone() .

Puoi eseguire il deep copy automatico con XStream, da http://x-stream.github.io/ :

XStream è una semplice libreria per serializzare oggetti in XML e viceversa.

Aggiungilo al tuo progetto (se usi Maven)

  com.thoughtworks.xstream xstream 1.3.1  

Poi

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

Con questo hai una copia senza la necessità di implementare alcuna interfaccia di clonazione.

Se è ansible aggiungere un’annotazione al file sorgente, è ansible utilizzare un processore di annotazioni o un generatore di codice come questo .

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

Verrà generata una class DummyBeanBuilders , che ha un metodo statico dummyBeanUpdater per creare copie poco profonde, proprio come fareste 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 nel tuo codice:

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