it-swarm.com.de

Wie kopiere ich ein Objekt in Java?

Beachten Sie den folgenden Code:

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'

Ich möchte also die Variable dum in dumtwo kopieren und dum ändern, ohne die dumtwo zu beeinflussen. Aber der obige Code tut das nicht. Wenn ich etwas in dum ändere, geschieht dies auch in dumtwo.

Ich denke, wenn ich dumtwo = dum sage, kopiert Java nur die Referenz . Gibt es eine Möglichkeit, eine neue Kopie von dum zu erstellen und sie dumtwo zuzuweisen?

699
Veera

Erstellen Sie einen Kopierkonstruktor:

class DummyBean {
  private String dummy;

  public DummyBean(DummyBean another) {
    this.dummy = another.dummy; // you can access  
  }
}

Jedes Objekt verfügt auch über eine Klonmethode, mit der das Objekt kopiert werden kann, aber nicht verwendet wird. Es ist viel zu einfach, eine Klasse zu erstellen und eine falsche Klonmethode auszuführen. Wenn Sie das tun wollen, lesen Sie mindestens, was Joshua Bloch dazu in Effective Java zu sagen hat.

560
egaga

Basic: Kopieren von Objekten in Java.

Nehmen wir an, ein object_obj1, der zwei Objekte enthält, includedObj1 und containObj2
enter image description here

flaches Kopieren:
Beim flachen Kopieren wird eine neue instance derselben Klasse erstellt, und alle Felder werden in die neue Instanz kopiert und zurückgegeben. Object class bietet eine clone-Methode und unterstützt das flache Kopieren.
enter image description here

Tiefes Kopieren:
Eine tiefe Kopie tritt auf, wenn ein Objekt wird zusammen mit den Objekten kopiert, auf die es verweist. Das folgende Bild zeigt obj1, nachdem darauf eine tiefe Kopie erstellt wurde. Nicht nur obj1 wurde kopiert, sondern auch die darin enthaltenen Objekte wurden kopiert. Wir können Java Object Serialization verwenden, um eine tiefe Kopie zu erstellen. Leider hat dieser Ansatz auch einige Probleme ( detaillierte Beispiele ). 
enter image description here

Mögliche Probleme:
clone ist schwierig zu implementieren.
Es ist besser, defensive Kopieren , Copy-Konstruktoren (als @egaga-Antwort) oder statische Factory-Methoden zu verwenden.

  1. Wenn Sie über ein Objekt verfügen, von dem Sie wissen, dass es eine öffentliche clone()-Methode gibt, Sie aber den Typ des Objekts zur Kompilierzeit nicht kennen, haben Sie ein Problem. Java hat eine Schnittstelle namens Cloneable. In der Praxis sollten wir diese Schnittstelle implementieren, wenn wir ein Objekt Cloneable erstellen möchten. Da Object.cloneprotected ist, müssen wir override mit einer öffentlichen Methode _ damit es zugänglich ist.
  2. Ein anderes Problem entsteht, wenn wir deep copy eines komplexes Objekt versuchen. Angenommen, die clone()-Methode aller Member-Objektvariablen führt auch eine tiefe Kopie aus. Dies ist zu riskant für eine Annahme. Sie müssen den Code in allen Klassen steuern.

Zum Beispiel hat org.Apache.commons.lang.SerializationUtils eine Methode für Deep-Klon mit Serialisierung ( Source ). Wenn Sie Bean klonen müssen, gibt es in org.Apache.commons.beanutils ( Source ) mehrere Dienstprogrammmethoden.

  • cloneBean wird eine Bean basierend auf den verfügbaren Eigenschafts-Getters und-Setters klonen, auch wenn die Bean-Klasse selbst kein Cloneable implementiert.
  • copyProperties kopiert Eigenschaftswerte von der Origin-Bean in die Ziel-Bean für alle Fälle, in denen die Eigenschaftsnamen gleich sind.
374
Chandra Sekhar

Im Paket import org.Apache.commons.lang.SerializationUtils; gibt es eine Methode:

SerializationUtils.clone(Object);

Beispiel:

this.myObjectCloned = SerializationUtils.clone(this.object);
105
pacheco

Folgen Sie einfach wie folgt:

public class Deletable implements Cloneable{

    private String str;
    public Deletable(){
    }
    public void setStr(String str){
        this.str = str;
    }
    public void display(){
        System.out.println("The String is "+str);
    }
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

und wo auch immer Sie ein anderes Objekt erhalten möchten, führen Sie einfach das Klonen aus. 

Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
                                 // object, the changes made to this object will
                                 // not be reflected to other object
96
Bhasker Tiwari

Warum gibt es keine Antwort für die Verwendung der Reflection-API?

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                field.set(clone, field.get(obj));
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

Es ist wirklich einfach.

BEARBEITEN: Untergeordnetes Objekt über Rekursion einschließen

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                if(field.getType().isPrimitive() || field.getType().equals(String.class)
                        || field.getType().getSuperclass().equals(Number.class)
                        || field.getType().equals(Boolean.class)){
                    field.set(clone, field.get(obj));
                }else{
                    Object childObj = field.get(obj);
                    if(childObj == obj){
                        field.set(clone, clone);
                    }else{
                        field.set(clone, cloneObject(field.get(obj)));
                    }
                }
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }
37
WillingLearner

Ich verwende die JSON-Bibliothek von Google, um sie zu serialisieren und dann eine neue Instanz des serialisierten Objekts zu erstellen. Es gibt tiefe Kopien mit ein paar Einschränkungen:

  • es kann keine rekursiven Referenzen geben

  • es werden keine Arrays unterschiedlicher Typen kopiert

  • arrays und Listen sollten typisiert werden, da sonst die Klasse nicht instanziiert werden kann

  • sie müssen möglicherweise Zeichenfolgen in einer Klasse kapseln, die Sie selbst deklarieren

Ich verwende diese Klasse auch zum Speichern von Benutzereinstellungen, Fenstern und dem, was zur Laufzeit nicht neu geladen werden soll. Es ist sehr einfach zu bedienen und effektiv.

import com.google.gson.*;

public class SerialUtils {

//___________________________________________________________________________________

public static String serializeObject(Object o) {
    Gson gson = new Gson();
    String serializedObject = gson.toJson(o);
    return serializedObject;
}
//___________________________________________________________________________________

public static Object unserializeObject(String s, Object o){
    Gson gson = new Gson();
    Object object = gson.fromJson(s, o.getClass());
    return object;
}
       //___________________________________________________________________________________
public static Object cloneObject(Object o){
    String s = serializeObject(o);
    Object object = unserializeObject(s,o);
    return object;
}
}
25
Peter

Ja, Sie machen nur einen Verweis auf das Objekt. Sie können das Objekt klonen, wenn es Cloneable implementiert.

In diesem Wiki-Artikel finden Sie Informationen zum Kopieren von Objekten.

Siehe hier: Objekt kopieren

22
Chrisb

Ja. Sie müssen Deep Copy Ihr Objekt.

13
bruno conde

Fügen Sie Ihrer Klasse Cloneable und den folgenden Code hinzu

public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

Verwenden Sie diese clonedObject = (YourClass) yourClassObject.clone();

12
Teja Maridu

Hier ist eine anständige Erklärung für clone(), wenn Sie es am Ende brauchen ...

Hier: Klon (Java-Methode)

10
Jon Bringhurst

Das funktioniert auch. Modell voraussetzen

class UserAccount{
   public int id;
   public String name;
}

Fügen Sie Ihrer App zunächst __.compile 'com.google.code.gson:gson:2.8.1' hinzu> Gradle & Sync. Dann

Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);

Sie können die Verwendung eines Feldes mit dem Schlüsselwort transient nach dem Zugriffsmodifizierer ausschließen.

Hinweis: Dies ist eine schlechte Praxis. Es wird auch nicht empfohlen, Cloneable oder JavaSerialization zu verwenden. Es ist langsam und beschädigt. Schreibe einen Kopiekonstruktor für beste Leistung ref .

So etwas wie

class UserAccount{
        public int id;
        public String name;
        //empty constructor
        public UserAccount(){}
        //parameterize constructor
        public UserAccount(int id, String name) {
            this.id = id;
            this.name = name;
        }

        //copy constructor
        public UserAccount(UserAccount in){
            this(in.id,in.name);
        }
    }

Teststatistik von 90000 Iteration:
Zeile UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); nimmt 808ms

Zeile UserAccount clone = new UserAccount(aO); dauert weniger als 1ms

Fazit: Verwenden Sie Gson, wenn Ihr Chef verrückt ist und Sie Geschwindigkeit bevorzugen. Verwenden Sie den zweiten Kopierkonstruktor, wenn Sie Qualität bevorzugen.

Sie können auch den Konstruktionscode Generator Plugin in Android Studio verwenden.

8
Qamar

Deep Cloning ist Ihre Antwort, die die Implementierung der Cloneable-Schnittstelle und das Überschreiben der clone()-Methode erfordert.

public class DummyBean implements Cloneable {

   private String dummy;

   public void setDummy(String dummy) {
      this.dummy = dummy;
   }

   public String getDummy() {
      return dummy;
   }

   @Override
   public Object clone() throws CloneNotSupportedException {
      DummyBean cloned = (DummyBean)super.clone();
      cloned.setDummy(cloned.getDummy());
      // the above is applicable in case of primitive member types, 
      // however, in case of non primitive types
      // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
      return cloned;
   }
}

Sie werden es so nennen DummyBean dumtwo = dum.clone();

7
abbas

Dazu müssen Sie das Objekt irgendwie klonen. Obwohl Java über einen Klonmechanismus verfügt, sollten Sie ihn nicht verwenden, wenn Sie dies nicht müssen. Erstellen Sie eine Kopiermethode, die das Kopieren für Sie erledigt, und führen Sie dann Folgendes aus:

dumtwo = dum.copy();

Hier gibt es einige weitere Hinweise zu verschiedenen Techniken, um eine Kopie zu erstellen.

7
Yishai

Verwenden Sie ein Deep-Cloning-Dienstprogramm: 

SomeObjectType copy = new Cloner().deepClone(someObject);

Dadurch wird jedes Java-Objekt tief kopiert. Überprüfen Sie es unter https://github.com/kostaskougios/cloning

7
Cojones

Abgesehen vom expliziten Kopieren besteht ein anderer Ansatz darin, das Objekt unveränderlich zu machen (keine set- oder andere Mutator-Methoden). Auf diese Weise entsteht nie die Frage. Die Unveränderlichkeit wird bei größeren Objekten schwieriger, aber die andere Seite ist, dass Sie dazu gebracht werden, sich in kohärente kleine Objekte und Verbundstoffe aufzuteilen.

class DB {
  private String dummy;

  public DB(DB one) {
    this.dummy = one.dummy; 
  }
}
3
Mahdi Abdi

Übergeben Sie das Objekt, das Sie kopieren möchten, und erhalten Sie das gewünschte Objekt:

private Object copyObject(Object objSource) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(objSource);
            oos.flush();
            oos.close();
            bos.close();
            byte[] byteData = bos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
            try {
                objDest = new ObjectInputStream(bais).readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return objDest;

    }

Parsen Sie nun die Variable objDest zum gewünschten Objekt.

Viel Spaß beim Codieren!

2
A-Droid Tech

Mit XStream können Sie automatisch tiefes Kopieren von http://x-stream.github.io/ :

XStream ist eine einfache Bibliothek zum Serialisieren von Objekten in XML und zurück nochmal.

Fügen Sie es Ihrem Projekt hinzu (wenn Sie Maven verwenden)

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.3.1</version>                
</dependency>

Dann

DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));

Damit haben Sie eine Kopie, ohne dass Sie eine Klonschnittstelle implementieren müssen.

2
Jaime Hablutzel

Sie können versuchen, Cloneable zu implementieren und die clone()-Methode zu verwenden. Wenn Sie jedoch die Klonmethode verwenden, sollten Sie standardmäßig die public Object clone()-Methode der Variable Object überschreiben.

1
John W

Wenn Sie der Quelldatei eine Anmerkung hinzufügen können, kann ein Anmerkungsprozessor oder ein Codegenerator wie this verwendet werden.

import net.zerobuilder.BeanBuilder

@BeanBuilder
public class DummyBean { 
  // bean stuff
}

Es wird eine Klasse DummyBeanBuilders generiert, die über eine statische Methode dummyBeanUpdater verfügt, um flache Kopien zu erstellen, wie Sie es auch manuell tun würden.

DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
1
Lars Bohl
public class MyClass implements Cloneable {

private boolean myField= false;
// and other fields or objects

public MyClass (){}

@Override
public MyClass clone() throws CloneNotSupportedException {
   try
   {
       MyClass clonedMyClass = (MyClass)super.clone();
       // if you have custom object, then you need create a new one in here
       return clonedMyClass ;
   } catch (CloneNotSupportedException e) {
       e.printStackTrace();
       return new MyClass();
   }

  }
}

und in deinem Code:

MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();