Frage

Wenn Sie eine Java-Klasse implementiert die Serializable Schnittstelle, aber nicht über eine öffentliche clone() Methode ist es in der Regel möglich, eine tiefe Kopie wie diese zu erstellen:

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);
        }
    }
}

Ich begegne oft von Drittanbietern Bibliotheksklassen wie folgt und oben auf Hacks wie die greifen. Ich habe sogar ObjectOutputStream gelegentlich erweitert, um die Kopie flacher zu machen. Es ist nie ernsthafte Probleme verursacht, andere als ineffizient (langsam zu kodieren / dekodieren und die temporären Serialisierung Graphen können viel Speicher verbrauchen.)

Und wenn es nicht sicher ist, diese Technik zu verwenden, wahrscheinlich die Klasse soll nicht deklariert Serializable wurde.

Was würde Ich mag es, wissen, wenn Ihre Klasse Serializable ist, was man ein öffentliche clone() Verfahren verhindern könnte von der Definition (entweder über die Cloneable Schnittstelle oder einen Kopierkonstruktor?)


Siehe auch: Kopieren Sie ein Objekt in Java

War es hilfreich?

Lösung

Nun, Sie sagen, die Serialisierung Mechanismus ist eine Möglichkeit, zu „klonen“ indirekt Objekte. Das ist natürlich nicht seine primäre Funktion. Es ist in der Regel lassen Programme übertragen über ein Netzwerk-Objekte, oder zu speichern und später las sie. Sie können ein Objekt erwarten, auf diese Weise verwendet werden, und Serializable implementieren, die zwar nicht den Code zu klonen erwarten Objekte lokal und nicht klonbar implementieren.

Die Tatsache, dass Code funktioniert, um dies über die Serialisierung schlägt der Code ein Objekt in einer Art und Weise verwendet der Autor nicht die Absicht hat, das entweder der Autor oder Anrufers „Fehler“ sein könnte, aber es bedeutet nicht, dass in General Serializable und klonbar gehen zusammen.

Getrennt, ich bin nicht sicher, clone () „aufgebrochen“, so viel wie heikel richtig zu implementieren. Eine Kopie Konstruktor ist natürlicher zu bedienen und rechts IMHO erhalten.

Andere Tipps

Ich würde es vorziehen, eine Kopie Konstruktor zu verwenden, anstatt Verwendung des obigen Mechanismus. Sie können noch feiner definieren, was tief zu sein ist oder seicht kopiert, und stellen Sie die Kopieren eines Objekts unterscheidet sich von der Serialisierung eines Objekts. Ein Copykonstruktor (zum Beispiel) kann ermöglichen, zwei Objekte eine Referenz auf einen Master-Objekt zu teilen, während dies nicht für ein Objekt serialisiert und übertragen über das Netzwerk geeignet sind.

Beachten Sie, dass die Cloneable Methode weit verbreitet jetzt als defekt angesehen wird. Siehe diesen Artikel mit Joshua Bloch für weitere Informationen. Insbesondere hat es keine clone() Methode!

Brians Punkt über klonbar ist sehr gut, aber selbst wenn klonbar richtig gearbeitet, es gibt immer noch Fälle, in denen Sie ein Objekt sein serializeable wollen könnten, aber nicht klonbar.

Wenn ein Objekt eine eindeutige Identität außerhalb des Anwendungsbereichs des Verfahrens hat, wie eine In-Memory-Darstellung eines Datenbank-Datensatz, Sie wollen es nicht klonbar sein, denn das entspricht einen neuen Datensatz mit identischen Eigenschaften zu machen, einschließlich identitätsbezogene Attribute wie die Datenbankschlüssel, die so gut wie nie das richtige ist. Zur gleichen Zeit können Sie ein System in mehrere Prozesse für die Stabilität oder aus anderen Gründen gebrochen haben, so dass Sie einen Prozess in die Datenbank sprechen können und Erzeugung diese „EINHEIT“ Objekte (siehe „Domain-Driven Design“ von Eric Evans für mehr Informationen über Objektidentität Kohärenz in einem Datum gesicherte Anwendung erhalten), aber ein separater Prozess diese Objekte verwenden kann Business-Logik-Operationen durchzuführen. Das Entitätsobjekt würde serializable sein müssen, um sie von einem Prozess zum anderen weitergegeben werden.

Ich denke, Serializable und klonbar Schnittstellen sollte unbedingt verschiedene Zwecke verwendet werden. Und wenn Sie eine komplexe Klasse haben dann jeder von ihnen die Umsetzung ist nicht so einfach. So im allgemeinen Fall hängt es von den Zwecken.

Eines der größten Probleme mit Serializable ist, dass sie nicht leicht unveränderlich gemacht werden können. Serialisierung zwingt Sie dazu, einen Kompromiss hier zu machen.

Ich würde versucht sein, Kopierkonstruktoren auf der Objektgraphen zu erstellen. Es ist nur ein bisschen mehr Grunzen Arbeit zu tun.

Das erscheint mir als eine Art gefährlich, da es eine Reihe von Fallen zu Serialisierung sind, (obwohl die meisten von ihnen unwahrscheinlich ist, würde ich will noch Test für sie, wenn ich Objekte in 3D-Party-Bibliotheken Serialisierung). Wohl kaum ein verbreitetes Problem sein, aber es ist möglich, ein Objekt mit einem flüchtigen Variable haben als ein Teil davon des Staates, die Teil einer Duplizierung sein könnte (nicht, dass dies ein gutes Design ist, nur, dass es möglich ist), und eine solche Feld würde nicht in einer Serialisierung / Deserialisierung kopiert werden. Ein weiteres Problem, das in den Sinn kommt, ist Aufzählungen, Konstanten und die Möglichkeit, mehrere Kopien von solchen Dingen immer, wenn Sie mit ihnen umgehen nicht während der Deserialisierung.

Wieder Rand Fälle, aber etwas, das man wollen würde achten.

Ich dachte nur von einem anderen Fall - Wenn es ein enum .

Oder allgemeiner, wenn Ihre Klasse implementiert

scroll top