Domanda

In java è un po ' difficile attuare una profonda oggetto funzione di copia.Qual è la procedura da adottare per garantire l'oggetto originale e clonato una quota di riferimento?

È stato utile?

Soluzione

Un modo sicuro è quello di serializzare l'oggetto, quindi la deserializzazione.Questo assicura che ogni cosa è un nuovo marchio di riferimento.

Ecco un articolo su come fare questo in modo efficiente.

Avvertenze:E ' possibile per le classi di ignorare la serializzazione in modo che le nuove istanze non creato, per esempioper singoletti.Anche questo, naturalmente, non funziona se le classi non sono Serializzabili.

Altri suggerimenti

Un paio di persone hanno detto di usare o l'override Object.clone().Non farlo. Object.clone() ha alcuni importanti problemi, e il suo uso è sconsigliato nella maggior parte dei casi.Si prega di vedere l'Articolo 11, dal "Efficace Java"Joshua Bloch per una risposta completa.Io credo che tu possa usare tranquillamente Object.clone() sui tipi primitivi array, ma a parte che avete bisogno per essere giudizioso sul corretto uso e l'override di clone.

I regimi che si basano su di serializzazione XML (o altro) sono difettose.

La risposta non è semplice qui.Se si desidera profonda copia di un oggetto che si dovrà attraversare l'oggetto grafico e copia di ogni bambino oggetto in modo esplicito tramite l'oggetto del costruttore di copia o di un factory statico metodo che di volta in volta profonda copie dell'oggetto figlio.Immutables (ad es. Strings) non devono essere copiati.Come parte, si dovrebbe favorire la immutabilità per questo motivo.

È possibile effettuare una copia completa con la serializzazione senza la creazione di file.

L'oggetto che si desidera copia profonda necessario implement serializable.Se la classe non è definitiva o non possono essere modificati, estendere la classe e implementare serializable.

Convertire la vostra classe in un flusso di byte:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();

Ripristinare la classe da un flusso di byte:

ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
(Object) object = (Object) new ObjectInputStream(bais).readObject();

Si può fare una serializzazione a base di profondo clone utilizzando org.apache.commons.lang3.SerializationUtils.clone(T) in Apache Commons Lang, ma attenzione, le prestazioni è abissale.

In generale, è consigliabile scrivere il proprio clone metodi per ogni classe di un oggetto in un oggetto grafico che necessitano di clonazione.

Un modo per implementare copia profonda è quello di aggiungere costruttori di copia per ogni classe associata.Un costruttore di copia prende un'istanza di 'questo' come unico argomento e copia tutti i valori da esso.Un bel po ' di lavoro, ma piuttosto semplice e sicuro.

EDIT:si noti che non è necessario utilizzare la funzione di accesso di metodi per leggere i campi.È possibile accedere a tutti i campi direttamente, in quanto l'istanza di origine è sempre dello stesso tipo dell'istanza con il costruttore di copia.Ovvio, ma potrebbe essere trascurato.

Esempio:

public class Order {

    private long number;

    public Order() {
    }

    /**
     * Copy constructor
     */
    public Order(Order source) {
        number = source.number;
    }
}


public class Customer {

    private String name;
    private List<Order> orders = new ArrayList<Order>();

    public Customer() {
    }

    /**
     * Copy constructor
     */
    public Customer(Customer source) {
        name = source.name;
        for (Order sourceOrder : source.orders) {
            orders.add(new Order(sourceOrder));
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Edit:Si noti che quando si utilizza costruttori di copia è necessario conoscere il tipo di runtime dell'oggetto che si sta copiando.Con l'approccio sopra descritto non è possibile copiare facilmente una lista mista (potrebbe essere in grado di farlo con qualche riflessione di codice).

Apache commons offre un modo veloce per profonda clonare un oggetto.

My_Object object2= org.apache.commons.lang.SerializationUtils.clone(object1);

È possibile utilizzare una libreria che ha una semplice API, ed esegue relativamente veloce clonazione con la riflessione (dovrebbe essere più veloce di metodi di serializzazione).

Cloner cloner = new Cloner();

MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o

XStream è davvero utile in questi casi.Qui è un semplice codice per fare la clonazione

private static final XStream XSTREAM = new XStream();
...

Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));

Una molto facile e semplice approccio è quello di utilizzare Jackson JSON per la serializzazione di Java complessa Oggetto JSON e leggerlo.

http://wiki.fasterxml.com/JacksonInFiveMinutes

Utilizzare XStream(http://x-stream.github.io/).È anche possibile controllare le proprietà che si può ignorare attraverso le annotazioni o specificare in modo esplicito il nome della proprietà di XStream classe.Inoltre non è necessario implementare clonabile interfaccia.

Per Framework Spring utenti.Usando la classe org.springframework.util.SerializationUtils:

@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T object) {
     return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
}

Profonda la copia può essere fatto solo con ogni classe di consenso.Se hai il controllo della gerarchia di classe è quindi possibile implementare la clonabile interfaccia e implementare il metodo Clone.Altrimenti si fa una copia completa è impossibile farlo in modo sicuro, perché l'oggetto può essere anche non condividere dati e risorse (ad es.le connessioni al database).In generale, comunque una copia profonda è considerato cattiva pratica in ambiente Java e dovrebbe essere evitato tramite le opportune pratiche di progettazione.

import com.thoughtworks.xstream.XStream;

public class deepCopy {
    private static  XStream xstream = new XStream();

    //serialize with Xstream them deserialize ...
    public static Object deepCopy(Object obj){
        return xstream.fromXML(xstream.toXML(obj));
    }
}

Per oggetti complicati e se le prestazioni non sono significative che io uso una libreria json, come ediletto per serializzare l'oggetto json testo, quindi deserializzare il testo del nuovo oggetto.

ediletto che, sulla base di riflessione funziona nella maggior parte dei casi, tranne che transient i campi non saranno copiati e gli oggetti con la circolare di riferimento per giusta causa, con StackOverflowError.

public static <T> T copy(T anObject, Class<T> classInfo) {
    Gson gson = new GsonBuilder().create();
    String text = gson.toJson(anObject);
    T newObject = gson.fromJson(text, classInfo);
    return newObject;
}
public static void main(String[] args) {
    String originalObject = "hello";
    String copiedObject = copy(originalObject, String.class);
}

Ho usato Dozer per la clonazione di oggetti java e fantastico che , Kryo la biblioteca è un altro grande alternativa.

1)

public static Object deepClone(Object object) {
   try {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(baos);
     oos.writeObject(object);
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream ois = new ObjectInputStream(bais);
     return ois.readObject();
   }
   catch (Exception e) {
     e.printStackTrace();
     return null;
   }
 }

2)

    // (1) create a MyPerson object named Al
    MyAddress address = new MyAddress("Vishrantwadi ", "Pune", "India");
    MyPerson al = new MyPerson("Al", "Arun", address);

    // (2) make a deep clone of Al
    MyPerson neighbor = (MyPerson)deepClone(al);

Qui il MyPerson e Mioindirizzo classe deve implementare serilazable interfaccia

BeanUtils fa davvero un buon lavoro profondo di clonazione fagioli.

BeanUtils.cloneBean(obj);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top