Domanda

C'è un programma di utilità per la clonazione profonda per le collezioni di Java:

  • Array
  • Elenchi
  • Mappe

NOTA: preferire una soluzione senza l'utilizzo di serializzazione, ma con l'uso di Object.clone metodo (). Posso essere sicuro che il mio oggetto personalizzato attuerà clone () metodo e utilizzerà solo le classi Java standard che sono clonabile ...

È stato utile?

Soluzione

Penso che la precedente risposta verde era male , il motivo per cui si potrebbe chiedere?

  • Si aggiunge un sacco di codice
  • Si richiede di elencare tutti i campi da copiare e fare questo
  • Questo non funziona per gli elenchi quando si utilizza clone () (Questo è ciò che clone () per HashMap dice: Restituisce una copia di questa istanza HashMap:. Le chiavi e valuesthemselves non vengono clonati) così si finisce per farlo manualmente (questo mi fa piangere)

Oh, e dal modo in cui serializzazione è anche male, potrebbe essere necessario aggiungere Serializable tutto il luogo (questo mi fa anche piangere).

Allora, qual è la soluzione:

libreria Java profonda Clonazione La libreria clonazione è un piccolo, open source (licenza Apache) libreria Java che gli oggetti deep-cloni. Gli oggetti non devono implementare l'interfaccia Cloneable. Effectivelly, questa libreria può clonare qualsiasi oggetto Java. Può essere utilizzato cioè nelle implementazioni della cache se non si desidera che l'oggetto in cache da modificare o ogni volta che si desidera creare una copia completa di oggetti.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Check it out a https://github.com/kostaskougios/cloning

Altri suggerimenti

Tutti gli approcci per copiare gli oggetti in Java hanno difetti gravi:

Clone

  1. Il clone () il metodo è protetto, quindi non si può chiamare direttamente a meno che la classe in questione sostituisce con un metodo pubblico.
  2. clone () non chiama il costruttore. Qualsiasi costruttore. Sarà allocare la memoria, assegnare il class campo interno (di cui potete leggere tramite getClass()) e copiare i campi della originale.

Per maggiori problemi con clone (), vedi punto 11 del libro di Joshua Bloch " Efficace Java, Second Edition "

Serialize

Serialize è anche peggio; ha molti dei difetti di clone() e poi alcuni. Joshua ha un intero capitolo con quattro voci, soltanto per questo argomento.

La mia soluzione

La mia soluzione è aggiungere una nuova interfaccia per i miei progetti:

public interface Copyable<T> {
    T copy ();
    T createForCopy ();
    void copyTo (T dest);
}

Il codice è simile al seguente:

class Demo implements Copyable<Demo> {
    public Demo copy () {
        Demo copy = createForCopy ();
        copyTo (copy);
        return copy;
    }
    public Demo createForCopy () {
        return new Demo ();
    }
    public void copyTo (Demo dest)
        super.copyTo (dest);
        ...copy fields of Demo here...
    }
}

Purtroppo, devo copiare questo codice a tutti i miei oggetti, ma è sempre lo stesso codice, in modo da poter utilizzare un modello di editor di Eclipse. Vantaggi:

  1. posso decidere quale costruttore di chiamare e come inizializzare quale campo.
  2. inizializzazione avviene in un ordine deterministico (classe radice alla classe esempio)
  3. posso riutilizzare gli oggetti esistenti e li sovrascrivere
  4. Tipo sicura
  5. Singletons rimanere single

Per i tipi standard di Java (come le collezioni, ecc), io uso una classe di utilità che può copiare quelli. I metodi hanno bandiere e callback, in modo da poter controllare la profondità di una copia dovrebbe essere.

Shallow clonazione una collezione è facile, ma se si vuole profondo clone, una biblioteca sarà probabilmente fare di meglio di quanto Codifica esso (dal momento che si desidera clonare gli elementi all'interno la collezione pure) .

Proprio come questa risposta , ho usato il biblioteca Cloner e specificamente prestazioni testato contro XStream (che può 'clone' serializzando poi deserializzazione) e serializzazione binaria. Anche se XStream è molto veloce a serializzazione da / xml, Cloner è molto più veloce alla clonazione:

0.0851 ms: Xstream (clone da serializzazione / deserializzazione)
0.0223 ms: la serializzazione binaria (clone da serializzazione / deserializzazione)
0,0017 ms: Cloner
* tempo medio per clonare un oggetto semplice (due campi) e nessun difetto, costruttore pubblico. Eseguire 10.000 volte.

Oltre ad essere veloce, qui sono più motivi per scegliere Cloner:

  1. esegue un profondo clone di qualsiasi oggetto (anche quelli non scrivere voi stessi)
  2. non c'è bisogno per mantenere il vostro metodo clone () up-to-date ogni volta che si aggiunge un campo
  3. è possibile clonare gli oggetti che non dispongono di un costruttore pubblico predefinito
  4. lavora con molla
  5. (ottimizzazione) non clonare oggetti immutabili noti (come Integer, String, ecc.)
  6. facile da usare. Esempio:

    cloner.deepClone (ANYOBJECT);

Io sono il creatore del lib cloner, quello che Brad presentato. Questa è una soluzione per gli oggetti di clonazione, senza dover scrivere codice aggiuntivo (non è necessario per gli oggetti serializzabili o impl clone () metodo)

E 'abbastanza veloce come ha detto Brad, e recentemente ho caricato una versione che è ancora più veloce. Si noti che l'attuazione manuale di un metodo clone () sarà più veloce di clone lib, ma poi di nuovo Avrai bisogno di scrivere un sacco di codice.

Cloner lib ha funzionato abbastanza bene per me dato che sto usando in un'implementazione cache per un sito con traffico molto pesante (~ 1 milione di richieste / giorno). La cache dovrebbe clonare circa 10 oggetti per ogni richiesta. E 'abbastanza affidabile e stabile. Ma vi prego di essere consapevoli del fatto che la clonazione non è senza rischi. Il lib può essere configurato per println ogni istanza di classe che clona durante dev. In questo modo è possibile verificare se si clona quello che si pensa che dovrebbe clonare - grafi di oggetti può essere molto profondo e può contenere riferimenti a un numero sorprendentemente grande quantità di oggetti. Con clone lib, è possibile indicare per non clonare gli oggetti che non si desidera, cioè single.

Un modo generale di profonda-clone una raccolta arbitraria è quello di serializzare ad un ruscello, poi leggerlo di nuovo in una nuova collezione. Ti verrà reidratante completamente nuovi oggetti che non hanno alcuna relazione con quelle vecchie, oltre ad essere copie identiche.

Scopri La risposta di Bruno per un collegamento al Apache Commons classi di utilità serializzazione , che sarà molto utile se questo è il percorso che si decide di prendere.

Una possibilità è quella di utilizzare serializzazione :

Apache Commons fornisce SerializationUtils

Ho usato questo clonazione biblioteca e l'ho trovato molto utile. Dal momento che aveva alcune limitazioni (avevo bisogno di un controllo più granulare il processo di clonazione: quale campo, in quale contesto e quanto profondamente dovrebbe essere clonato, ecc), ho creato una versione estesa di esso. È possibile controllare la clonazione dei campi da indicandoli in la classe di entità.

solo per ottenere un sapore di esso, qui è una classe di esempio:

public class CloneMePlease {
    @Clone(Skip.class)
    String id3 = UUID.randomUUID().toString();

    @Clone(Null.class)
    String id4 = UUID.randomUUID().toString();

    @Clone(value = RandomUUID.class, groups=CustomActivationGroup1.class)
    String id5 = UUID.randomUUID().toString();

    @Clone.List({
            @Clone(groups=CustomActivationGroup2.class, value=Skip.class),
            @Clone(groups=CustomActivationGroup3.class, value=Copy.class)})
    Object activationGroupOrderTest = new Object();

    @Clone(LongIncrement.class)
    long version = 1l;

    @PostClone
    private void postClone(CloneMePlease original, @CloneInject CloneInjectedService service){
         //do stuff with the original source object in the context of the cloned object
         //you can inject whatewer service you want, from spring/guice to perform custom logic here
    }
}

Maggiori dettagli qui: https://github.com/mnorbi/fluidity-cloning

C'è anche un interno specifico hibernate nel caso in cui si ha la necessità di esso.

Con la serializzazione e deserializzazione poi, ma essere consapevoli del fatto che questo approccio funziona solo con le classi Serializable senza campi transitori. Inoltre, i vostri single non saranno single più.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top