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 <=>?

È stato utile?

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 .
entrare descrizione dell'immagine qui

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.
entrare descrizione dell'immagine qui

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 ) .
entrare descrizione dell'immagine qui

Possibili problemi:
Object.clone è difficile da implementare in modo corretto.
E 'meglio usare difensiva copia , copia costruttori (come @egaga risposta) o metodi factory statici .

  1. 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 chiamata copyProperties. 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.
  2. 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.

consultare qui: Oggetto copia

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 ...

Qui: clone (metodo Java)

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();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top