Domanda

Se una classe Java implementa il file Serializable interfaccia ma non ha un pubblico clone() metodo, di solito è possibile creare una copia profonda come questa:

class CloneHelper {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T copy = (T) ois.readObject();
            ois.close();
            return copy;
        } catch (ClassNotFoundException ex) {
            // Shouldn't happen
            throw new Error(ex);
        } catch (IOException ex) {
            // Probably a bug in T's custom serialization methods
            throw new RuntimeException(ex);
        }
    }
}

Incontro spesso classi di librerie di terze parti come questa e ricorro a hack come quello sopra.Ho anche prolungato ObjectOutputStream a volte per rendere la copia meno profonda.Non ha mai causato problemi seri, oltre a essere inefficiente (lento da codificare/decodificare e i grafici di serializzazione temporanei possono consumare molta memoria).

E se non è sicuro utilizzare questa tecnica, probabilmente la classe non avrebbe dovuto essere dichiarata Serializable.

Quindi quello che vorrei sapere è se la tua classe lo è Serializable, cosa potrebbe impedirti di definire un pubblico clone() metodo (usando il file Cloneable interfaccia o un costruttore di copie?)


Imparentato: Copia un oggetto in Java

È stato utile?

Soluzione

Beh, stai dicendo che il meccanismo di serializzazione è un modo per "clonare" oggetti indirettamente. Questo è, naturalmente, non la sua funzione primaria. Di solito è usato per lasciare programmi di trasmettere gli oggetti attraverso una rete, o conservare e poi leggerli. Ci si può aspettare un oggetto da usare in questo modo, e implementare Serializable, pur non aspettandosi codice per clonare gli oggetti a livello locale, e non implementare Cloneable.

Il fatto che il codice sta lavorando intorno a questa via di serializzazione suggerisce il codice utilizza un oggetto in un modo in cui l'autore non ha inteso, che potrebbe essere sia l'autore o "colpa" del chiamante, ma non implica che in generale Serializable e Cloneable andare insieme.

A parte, non sono sicuro clone () è "rotto" il più difficile da implementare in modo corretto. Un costruttore di copia è più naturale da usare e ottenere IMHO destra.

Altri suggerimenti

Io preferirei usare un costruttore di copia, piuttosto che utilizzare il meccanismo di cui sopra. È possibile definire più finemente cosa c'è da copiare profondamente o superficialmente, e rendere il copia di un oggetto distinto dal serializzazione di un oggetto. Un costruttore di copia può (per esempio) permettono due oggetti di condividere un riferimento a un oggetto master, mentre ciò non può essere adatto per un oggetto serializzato e trasmessi attraverso la rete.

Si noti che il metodo Cloneable è ampiamente considerato ora come rotto. Vedere questo articolo con Joshua Bloch per ulteriori informazioni. In particolare, essa non ha un metodo clone()!

punto di Brian circa Cloneable è molto buono, ma anche se Cloneable lavorato bene, ci sono ancora casi in cui si potrebbe desiderare un oggetto da serializeable ma non clonabile.

Se un oggetto ha un'identità unica al di fuori del campo di applicazione del processo, come una rappresentazione in memoria di un record di database, non si vuole che sia clonabile perché è equivalente a fare un nuovo record con gli attributi identici, compresi gli attributi identitari, come la chiave di database, che non è quasi mai la cosa giusta. Allo stesso tempo, si può avere un sistema suddiviso in più processi per la stabilità o per altri motivi, in modo da avere un unico processo di parlare con il database e la generazione di questi oggetti "entità" (vedi "Domain-Driven Design" di Eric Evans per più informazioni sul mantenimento della coerenza oggetto identità in un'applicazione di dati di backup), ma un processo separato possono utilizzare questi oggetti per eseguire operazioni logiche di business. L'oggetto entità avrebbe bisogno di essere serializzabile per essere passato da un processo all'altro.

Credo che le interfacce Serializable e clonabile devono essere utilizzati per scopi assolutamente diversi. E se si dispone di una classe complesso quindi l'attuazione di ciascuna di loro non è così facile. Quindi, in caso generale dipende dalle finalità.

Uno dei maggiori problemi con Serializable è che essi non possono essere fatti facilmente immutabile. le forze di serializzazione di fare un compromesso qui.

sarei tentato di creare copia costruttori lungo il grafo di oggetti. Il suo solo un po 'più di lavoro sporco da fare.

Ciò mi sembra pericoloso, poiché ci sono una serie di insidie ​​​​nella serializzazione (sebbene la maggior parte di esse sia improbabile, vorrei comunque testarle se serializzassi oggetti nelle librerie di terze parti 3D).Probabilmente non è un problema comune, ma è possibile avere un oggetto con una variabile volatile come parte del suo stato che potrebbe far parte di un'operazione di clonazione (non che sia un buon progetto, solo che è possibile), e una cosa del genere il campo non verrebbe copiato in un processo di serializzazione/deserializzazione.Un altro problema che mi viene in mente sono le enumerazioni, le costanti e la possibilità di ottenere più copie di tali cose se non le gestisci durante la deserializzazione.

Ancora una volta, casi limite, ma qualcosa a cui dovresti prestare attenzione.

Ho solo pensato di un altro caso - quando si tratta di un enum .

O, più in generale, quando i vostri attrezzi di classe readResolve . Ciò significa che l'oggetto si torna da readObject non è lo stesso che è stato letto dal flusso, e, quindi, non è necessariamente una copia dell'oggetto che è stato originariamente scritto per il flusso.

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