Come faccio a copiare un oggetto in Java?
Domanda
Si consideri il seguente codice:
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
per dumtwo
e cambiare dumtwo = dum
senza intaccare la <=>. Ma il codice di cui sopra non sta facendo questo. Quando cambio qualcosa in <=>, lo stesso cambiamento sta accadendo in <=> anche.
Credo che, quando dico <=>, copie Java solo di riferimento . Quindi, c'è un modo per creare una nuova copia di <=> e assegnarlo a <=>?
Soluzione
Crea un costruttore di copia:
class DummyBean {
private String dummy;
public DummyBean(DummyBean another) {
this.dummy = another.dummy; // you can access
}
}
Ogni oggetto ha un metodo clone che può essere usato per copiare l'oggetto, ma non ne fanno uso. E 'troppo facile creare una classe e fare metodo clone improprio. Se avete intenzione di farlo, leggere almeno quanto Joshua Bloch ha da dire su di esso in Effective Java .
Altri suggerimenti
base:. copia di un oggetto in Java
Supponiamo un obj1
agli oggetti, che contiene due oggetti, containedObj1 e containedObj2 .
copia superficiale:
copia superficiale crea un nuovo instance
della stessa classe e copia tutti i campi per la nuova istanza e lo restituisce. classe Object fornisce un metodo clone
e fornisce il supporto per la copia poco profonda.
copia profonda:
Una copia profonda verifica quando un oggetto viene copiato insieme con gli oggetti a cui si riferisce . Qui di seguito gli spettacoli di immagine Java Object Serialization
dopo una copia profonda è stata eseguita su di essa. Non solo è stato copiato clone()
, ma gli oggetti in esso contenuti sono stati copiati pure. Possiamo usare Cloneable
di fare una copia profonda. Sfortunatamente, questo approccio ha qualche problema di troppo ( esempi dettagliati ) .
Possibili problemi:
Object.clone
è difficile da implementare in modo corretto.
E 'meglio usare difensiva copia , copia costruttori (come @egaga risposta) o metodi factory statici .
- Se si dispone di un oggetto, che si sa ha un metodo pubblico
cloneBean
, ma non si conosce il tipo di oggetto al momento della compilazione, allora avete un problema. Java ha un'interfaccia chiamatacopyProperties
. In pratica, dobbiamo implementare questa interfaccia, se vogliamo fare un oggetto <=>. <=> è protetto , quindi dobbiamo di override con un metodo pubblico in modo che esso sia accessibile.
- Un altro problema si pone quando si cerca profonda copia di un oggetto complesso . Si supponga che il metodo di tutte le variabili oggetto membro <=> fa anche copia completa, questo è troppo rischioso di una supposizione. È necessario controllare il codice in tutte le classi.
Ad esempio org.apache.commons.lang.SerializationUtils avrà metodo per clonare profondo utilizzando la serializzazione ( Fonte ). Se abbiamo bisogno di clonare Bean poi ci sono un paio di metodi di utilità in org.apache.commons.beanutils ( Fonte ).
- <=> si Clonare un fagiolo sulla base dei getter e setter di proprietà disponibili, anche se la classe bean per sé non implementa Cloneable.
- <=> copierà valori delle proprietà dal fagiolo origine al fagiolo di destinazione per tutti i casi in cui i nomi delle proprietà uguali.
Nel pacchetto import org.apache.commons.lang.SerializationUtils;
c'è un metodo:
SerializationUtils.clone(Object);
Esempio:
this.myObjectCloned = SerializationUtils.clone(this.object);
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 dove si vuole ottenere un altro oggetto, semplice eseguire 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
Perché non c'è nessuna risposta per l'utilizzo di API 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;
}
}
E 'davvero semplice.
EDIT: Includere oggetto 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;
}
}
Io uso biblioteca JSON di Google per serializzare poi creare una nuova istanza dell'oggetto serializzato. Lo fa copia completa con alcune restrizioni:
-
Non ci possono essere riferimenti ricorsivi
-
non copierà array di tipi diversi
-
array e liste devono essere digitati o non troverà la classe di creare un'istanza di
-
potrebbe essere necessario incapsulare le stringhe in una classe si dichiara te
Io uso anche questa classe per salvare le preferenze dell'utente, finestre e quant'altro per essere ricaricati in fase di esecuzione. E '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ì, si sta solo facendo un riferimento all'oggetto. È possibile clonare l'oggetto se implementa Cloneable
.
Leggi questo articolo wiki sulla copia di oggetti.
Sì. Devi copia completa l'oggetto.
Aggiungi Cloneable
e sotto il codice alla classe
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
Utilizzare questa clonedObject = (YourClass) yourClassObject.clone();
Questo funziona anche. Assumendo il modello
class UserAccount{
public int id;
public String name;
}
Per prima cosa aggiungere
compile 'com.google.code.gson:gson:2.8.1'
alla tua app> Gradle e sincronizzazione. Poi
Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);
È possibile escludere utilizzando un campo utilizzando transient
parola chiave dopo modificatore di accesso.
Nota: Questa è una cattiva pratica. Inoltre, non consiglia di utilizzare Cloneable
o JavaSerialization
E 'lento e rotti. Scrivi costruttore di copia per la migliore rif .
Qualcosa di simile
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 test di 90000 iterazione:
Linea UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);
prende 808ms
Linea UserAccount clone = new UserAccount(aO);
richiede meno di 1ms
Conclusione: Usa GSON se il vostro capo è pazzo e si preferisce la velocità. Utilizzare secondo costruttore di copia, se si preferisce la qualità.
È inoltre possibile utilizzare il codice costruttore di copia plug in Android Studio.
Ecco una spiegazione decente di clone()
se si finisce per averne bisogno ...
La clonazione profonda è la vostra risposta, che richiede l'attuazione della Cloneable
dell'interfaccia 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;
}
}
Si chiamare in questo modo
DummyBean dumtwo = dum.clone();
Usa un programma di utilità clonazione profonda:
SomeObjectType copy = new Cloner().deepClone(someObject);
In questo modo profondo copiare qualsiasi oggetto Java, check it out a https://github.com/kostaskougios/cloning
Per fare questo è necessario clonare l'oggetto in qualche modo. Anche se Java ha un meccanismo di clonazione, non utilizzarlo se non è necessario. Creare un metodo di copia che fa il lavoro di copia per voi, e poi fare:
dumtwo = dum.copy();
Qui è una certa ulteriori consigli su diverse tecniche per realizzare una copia.
Oltre a copiare in modo esplicito, un altro approccio è quello di rendere l'oggetto immutabili (nessun set
o altri metodi mutatori). In questo modo, la questione non si pone. Immutabilità diventa più difficile con gli oggetti più grandi, ma che dall'altra parte di quel è che ti spinge nella direzione di suddivisione in piccoli oggetti e materiali compositi coerenti.
class DB {
private String dummy;
public DB(DB one) {
this.dummy = one.dummy;
}
}
profondo È possibile copiare automaticamente Xstream, da http://x-stream.github.io/:
xstream è una semplice libreria per serializzare oggetti in XML e viceversa ancora una volta.
Aggiungi al tuo progetto (se si utilizza Maven)
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>
Poi
DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));
Con questo si dispone di una copia, senza la necessità di attuare alcuna interfaccia clonazione.
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 codice:
MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();
Passa l'oggetto che si desidera copiare e ottenere l'oggetto desiderato:
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 analizzare l'objDest
per oggetto desiderato.
Happy Coding!
Si può cercare di implementare Cloneable
e utilizzare il metodo clone()
; tuttavia, se si utilizza il metodo clone si dovrebbe - dalla norma -. SEMPRE sovrascrivere il metodo Object
s 'public Object clone()
Se è possibile aggiungere un'annotazione al file di origine, un processore annotazione o generatore di codice come questo può essere utilizzato.
import net.zerobuilder.BeanBuilder
@BeanBuilder
public class DummyBean {
// bean stuff
}
Una classe DummyBeanBuilders
sarà genera, che ha un metodo statico dummyBeanUpdater
per creare copie poco profonde, allo stesso modo come si farebbe manualmente.
DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();