Frage

In Java ist es ein bisschen schwierig, eine tiefe Objekt Kopierfunktion zu implementieren. Welche Schritte nehmen Sie das ursprüngliche Objekt und die geklonte 1 Aktie kein Hinweis zu gewährleisten?

War es hilfreich?

Lösung

Ein sicherer Weg ist, um das Objekt zu serialisieren, dann deserialisieren. Dies stellt sicher, alles ist ein brandneues Referenz.

Hier ist ein Artikel darüber, wie dies effizient zu tun .

Vorsichtsmaßnahmen: Es ist möglich, für die Klassen Serialisierung so außer Kraft zu setzen, dass neue Instanzen nicht erstellt, z.B. für Singletons. Auch dies natürlich nicht funktioniert, wenn Ihre Klassen nicht Serializable sind.

Andere Tipps

Ein paar Leute haben mit oder überwiegendem Object.clone() erwähnt. Tun Sie es nicht. Object.clone() hat einige große Probleme, und seine Verwendung ist in den meisten Fällen abgeraten. Bitte beachten Sie Punkt 11, von " Effective Java " von Joshua Bloch für eine vollständige Antwort. Ich glaube, Sie sicher Object.clone() auf primitive Art Arrays verwenden können, aber abgesehen davon, dass Sie richtig mit und überwiegendes Klon vernünftig sein müssen.

Die Regelungen, die auf die Serialisierung verlassen (XML oder andere) sind kludgy.

Es gibt keine einfache Antwort hier. Wenn Sie tiefe Kopie wollen ein Objekt finden Sie das Objektgraph durchqueren müssen, und kopieren Sie jedes Kind-Objekt explizit über das Copykonstruktor des Objekts oder eine statische Factory-Methode, die in tiefen Kopien das untergeordnete Objekt drehen. Immutables (z Strings) müssen nicht kopiert werden. Als Nebenwirkung, sollten Sie Unveränderlichkeit aus diesem Grund bevorzugen.

Sie können eine tiefe Kopie mit Serialisierung machen, ohne Dateien zu erstellen.

Ihr Objekt, das Sie tiefe Kopie wünschen müssen implement serializable. Wenn die Klasse nicht endgültig ist oder nicht geändert werden kann, die Klasse erweitern und implementieren serializable.

Konvertieren Sie Ihre Klasse in einen Stream von Bytes:

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

Stellen Sie Ihre Klasse aus einem Strom von Bytes:

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

Sie können eine Serialisierung-basierten tiefen Klon tun mit org.apache.commons.lang3.SerializationUtils.clone(T) in Apache Commons Lang, aber seien Sie vorsichtig-die Leistung ist miserabel.

In der Regel ist es am beste Praxis, um Ihre eigenen Klon-Methoden für jede Klasse eines Objekts im Objektgraphen zu schreiben Klonen zu benötigen.

Eine Möglichkeit, tiefe Kopie zu implementieren ist Kopierkonstruktoren zu jeder zugehörigen Klasse hinzuzufügen. Eine Kopie Konstruktor nimmt eine Instanz von ‚dies‘ als sein einziges Argument und kopiert alle Werte von ihm. Ganz einige Arbeit, aber ziemlich einfach und sicher.

EDIT: beachten Sie, dass Sie benötigen, um Felder zu lesen nicht Accessormethoden zu verwenden. Sie können alle Felder direkt zugreifen, da die Quellinstanz immer vom gleichen Typ wie die Instanz mit dem Copy-Konstruktor ist. Offensichtliche, aber vielleicht übersehen werden.

Beispiel:

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: Beachten Sie, dass, wenn Kopierkonstruktoren verwenden Sie den Laufzeittyp des Objekts wissen müssen Sie kopieren. Mit dem obigen Ansatz kann man nicht einfach eine gemischte Liste kopieren (Sie könnten in der Lage sein, es mit einigen Überlegungen Code zu tun).

Apache commons bietet einen schnellen Weg zu tiefer Klon ein Objekt aus.

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

Sie können Bibliothek verwenden, die eine einfache API hat und führt relativ schnell Klonen mit Reflexion (sollte schneller als Serialisierungsmethoden).

Cloner cloner = new Cloner();

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

Xstream ist in solchen Fällen sehr nützlich. Hier ist ein einfacher Code zu tun Klonen

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

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

Eine sehr leichte und einfache Ansatz ist Jackson JSON zu verwenden, um komplexe Java-Objekt zu JSON serialisiert und lesen Sie es zurück.

http://wiki.fasterxml.com/JacksonInFiveMinutes

Verwenden XStream ( http://x-stream.github.io/ ). Sie können auch, welche Eigenschaften Sie können durch Anmerkungen ignorieren steuern oder explizit den Namen der Eigenschaft zu XStream Klasse angeben. Außerdem brauchen Sie nicht clonable Schnittstelle zu implementieren.

Spring Framework Benutzer. Mit Klasse org.springframework.util.SerializationUtils:

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

Deep Kopieren kann nur mit jeder Klasse Zustimmung erfolgen. Wenn Sie die Kontrolle über die Klassenhierarchie haben, dann können Sie die clonable-Schnittstelle implementieren und die Clone-Methode implementieren. Ansonsten eine tiefe Kopie zu tun ist unmöglich, sicher zu tun, weil das Objekt auch Nicht-Datenressourcen (zum Beispiel Datenbankverbindungen) teilen werden. Im Allgemeinen jedoch tief Kopieren schlechte Praxis in der Java-Umgebung und soll über die entsprechenden Designpraktiken vermieden werden.

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

Für komplizierte Objekte und wenn die Leistung nicht signifikant i eine json-Bibliothek verwenden, wie Gson serialisiert Deserialisieren das Objekt zu json Text, dann den Text neues Objekt zu erhalten.

Gson, die auf Reflexion basiert werden Werke in den meisten Fällen, außer dass transient Feldern nicht mit kreisförmiger Referenz mit Ursache StackOverflowError kopiert und Objekten werden.

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

I verwendet Dozer für Java-Objekte klonen und es ist toll an, dass Kryo Bibliothek ist eine weitere gute Alternative.

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

Hier Ihre MyPerson und meineadresse Klasse muss serializable Schnittstelle implementieren

BeanUtils macht einen wirklich guten Job tief Klonen Bohnen.

BeanUtils.cloneBean(obj);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top