Comment puis-je copier un objet en Java?

Considérez le code ci-dessous:

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'

Donc, je veux copier le dum à dumtwo et dum sans affecter le dumtwo . Mais le code ci-dessus ne le fait pas. Quand je change quelque chose dans dum , le même changement se produit dans dumtwo aussi.

je suppose que, quand je dis dumtwo = dum , Java copie le référence seulement . Donc, est-il possible d'en créer une nouvelle une copie de dum et assignez-la à dumtwo ?

663
demandé sur Mooncrater 2009-05-15 18:30:26

21 réponses

créer un constructeur de copie:

class DummyBean {
  private String dummy;

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

Chaque objet a également une méthode clone qui peut être utilisé pour copier l'objet, mais ne l'utilisez pas. C'est trop facile de créer une classe et faire une mauvaise méthode clone. Si vous allez faire cela, lisez au moins ce que Joshua Bloch a à dire à ce sujet dans Java efficace .

537
répondu egaga 2009-05-15 14:47:40

de Base": Objet de la Copie en Java.

supposons un objet - obj1 , qui contient deux objets, containedObj1 et containedObj2 .

enter image description here

copie peu profonde:

la copie superficielle crée un nouveau instance de la même classe et copie tous les champs de la nouvelle instance et le renvoie. classe d'Objets fournit un clone méthode et fournit un soutien pour les eaux peu profondes de la copie.

enter image description here

au plus Profond de la copie:

Une copie profonde se produit quand un objet est copié avec les objets auxquels il se réfère . Ci-dessous l'image montre obj1 après une copie profonde a été effectuée sur elle. n'a Pas seulement obj1 copié , mais les objets qu'il contient ont été copiés. Nous pouvons utiliser Java Object Serialization pour faire une copie profonde. Malheureusement, cette approche pose également quelques problèmes( exemples détaillés ).

enter image description here

Problèmes Possibles:

clone est difficile à mettre en œuvre correctement.

Il est préférable d'utiliser copie défensive , copy constructors (comme @egaga répondre) ou static factory methods .

  1. si vous avez un objet, que vous connaissez a une méthode publique clone() , mais vous ne savez pas le type de l'objet à compiler temps, alors vous avez un problème. Java a une interface appelée Cloneable . En pratique, nous devrions implémenter cette interface si nous voulons faire un objet Cloneable . Object.clone est protégé , nous devons donc outrepasser il avec une méthode publique afin qu'il soit accessible.

  2. un autre problème se pose lorsque nous essayons copie profonde d'un objet complexe . Supposons que la méthode clone() de toutes les variables d'objet membre copie aussi en profondeur, c'est trop risqué d'une hypothèse. Vous devez contrôler le code dans toutes les classes.

Pour l'exemple org.Apache.commun.lang.SerializationUtils aura méthode pour Deep clone en utilisant serialization ( Source ). Si nous avons besoin de cloner alors Il ya quelques méthodes d'utilité dans org.Apache.commun.beanutils ( Source ).

  • cloneBean Clonera un haricot en fonction de la propriété disponible getters et setters, même si la classe de haricot elle-même ne met pas en œuvre clonable.
  • copyProperties copie les valeurs de propriété de la fève d'origine à la fève de destination pour tous les cas où les noms de propriété sont les mêmes.
359
répondu Chandra Sekhar 2013-05-02 04:50:10

dans le paquet import org.apache.commons.lang.SerializationUtils; il y a une méthode:

SerializationUtils.clone(Object);

exemple:

this.myObjectCloned = SerializationUtils.clone(this.object);
94
répondu pacheco 2013-05-02 20:14:54

comme suit:

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

et partout où vous voulez obtenir un autre objet, simple effectuer le clonage. e.g:

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
93
répondu Bhasker Tiwari 2011-10-20 15:46:05

pourquoi n'y a-t-il pas de réponse à l'utilisation de L'API réflexion?

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

c'est très simple.

EDIT: l'enfance de l'objet via la récursivité

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;
        }
    }
34
répondu WillingLearner 2014-08-29 09:49:50

j'utilise la bibliothèque JSON de Google pour la sérialiser puis créer une nouvelle instance de l'objet sérialisé. Il fait une copie profonde avec quelques restrictions:

  • il ne peut pas y avoir de références récursives

  • cela ne peut pas copier des tableaux de types disparates

  • les tableaux et les listes doivent être dactylographiés ou il ne trouvera pas la classe pour instancier

  • vous pourriez avoir besoin d'encapsuler des chaînes dans une classe que vous déclarez vous-même

j'utilise également cette classe pour enregistrer les préférences de l'utilisateur, windows et ce qui ne doit pas être rechargé à l'exécution. Il est très facile à utiliser et efficace.

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;
}
}
22
répondu Peter 2013-07-09 20:14:24

Oui, vous faites juste référence à l'objet. Vous pouvez cloner l'objet s'il implémente Cloneable .

consultez cet article wiki sur la copie d'objets.

Consultez ici: Objet de la copie

21
répondu Chrisb 2016-07-28 09:40:26

Oui. Vous avez besoin de Copie votre objet.

12
répondu bruno conde 2009-05-15 14:35:02

ajouter Cloneable et au-dessous du code de votre classe

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

utilisez cette clonedObject = (YourClass) yourClassObject.clone();

12
répondu Teja Maridu 2013-07-31 15:00:04

voici une bonne explication de clone() si vous en avez besoin...

ici: clone (méthode Java)

9
répondu Jon Bringhurst 2016-07-28 09:41:02

ça marche aussi. Modèle hypothétique

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

premier ajouter compile 'com.google.code.gson:gson:2.8.1' de votre application>gradle et synchronisation. Puis

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

vous pouvez exclure l'utilisation d'un champ en utilisant le mot-clé transient après le modificateur d'accès.

Note: c'est une mauvaise pratique. Aussi ne recommande pas d'utiliser Cloneable ou JavaSerialization il est lent et cassé. Écrire constructeur de copie pour obtenir les meilleures performances ref .

quelque chose comme

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

statistiques D'essai de 90000 itération:

Ligne UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); takes 808ms "1519170920

Ligne UserAccount clone = new UserAccount(aO); prend moins de 1ms

Conclusion: utilisez gson si votre patron est fou et que vous préférez la vitesse. Utilisez le deuxième constructeur de copie si vous préférez la qualité.

vous pouvez également utiliser le code du constructeur de copie plugin générateur dans Android Studio.

8
répondu Qamar 2017-09-23 06:24:15

Pour ce faire vous devez cloner l'objet d'une certaine façon. Bien que Java ait un mécanisme de Clonage, ne l'utilisez pas si vous n'en avez pas besoin. Créez une méthode de copie qui fait le travail de copie pour vous, puis faites:

dumtwo = dum.copy();

ici est un peu plus de conseils sur les différentes techniques pour accomplir une copie.

7
répondu Yishai 2017-05-23 12:26:42

le clonage profond est votre réponse, qui nécessite la mise en œuvre de l'interface Cloneable et la suppression de la méthode clone() .

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

Vous l'appellerez comme ceci DummyBean dumtwo = dum.clone();

7
répondu abbas 2015-01-30 19:51:59

Utiliser un profond utilitaire de clonage:

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

cela va copier profondément n'importe quel objet java, vérifiez à https://github.com/kostaskougios/cloning

6
répondu Cojones 2016-12-13 14:43:22

outre la copie explicite, une autre approche consiste à rendre l'objet immuable (no set ou autres méthodes mutatrices). Dans cette optique, la question se pose jamais. L'immuabilité devient plus difficile avec les objets plus grands, mais l'autre côté de cela est qu'il vous pousse dans la direction de la division en petits objets cohérents et des composites.

5
répondu Tom Hawtin - tackline 2009-05-15 14:43:35
class DB {
  private String dummy;

  public DB(DB one) {
    this.dummy = one.dummy; 
  }
}
3
répondu Mahdi Abdi 2014-03-02 13:35:20

Passer de l'objet qui vous veut copier et obtenir l'objet qui vous veut ,

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;

    }

analysez maintenant l'objet le plus obscur à décrire.

Codage Heureux

2
répondu A-Droid Tech 2015-12-07 13:25:22

vous pouvez essayer d'implémenter Cloneable et utiliser la méthode clone() ; cependant, si vous utilisez la méthode clone vous devriez - par standard - toujours outrepasser Object 's public Object clone() méthode.

1
répondu 2011-10-20 15:47:35

vous pouvez copier en profondeur automatiquement avec XStream, à partir de http://x-stream.github.io / :

XStream est une bibliothèque simple pour sérialiser des objets vers XML et retour encore.

ajoutez - le à votre projet (si vous utilisez maven)

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

puis

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

avec ceci vous avez une copie sans avoir besoin d'implémenter une interface de Clonage.

1
répondu Jaime Hablutzel 2015-08-11 18:35:31

si vous pouvez ajouter une annotation au fichier source, un processeur d'annotation ou un générateur de code comme celui-ci peut être utilisé.

import net.zerobuilder.BeanBuilder

@BeanBuilder
public class DummyBean { 
  // bean stuff
}

une classe DummyBeanBuilders sera générée, qui a une méthode statique dummyBeanUpdater pour créer des copies superficielles, de la même manière que vous le feriez manuellement.

DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
0
répondu Lars Bohl 2017-02-14 05:45:49
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();
   }

  }
}

et dans votre code:

MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();
0
répondu Amir Hossein Ghasemi 2018-08-10 13:26:48