Question Comment 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 changer dum sans affecter le dumtwo. Mais le code ci-dessus ne le fait pas. Quand je change quelque chose dum, le même changement se produit dans dumtwo aussi.

Je suppose, quand je dis dumtwo = dum, Java copie le référence seulement. Donc, est-il possible de créer une nouvelle copie de dum et l'assigner à dumtwo?


649
2018-05-15 14:30


origine


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ée pour copier l'objet, mais ne l'utilise pas. Il est trop facile de créer une classe et de faire une mauvaise méthode de clonage. Si vous allez faire cela, lisez au moins ce que Joshua Bloch a à dire à ce sujet dans Java efficace.


525
2018-05-15 14:35



De base: Copie d'objet en Java.

Supposons un objet obj1, qui contient deux objets, containedObj1 et containedObj2.
enter image description here

copie superficielle:
la copie superficielle crée une nouvelle instance de la même classe et copie tous les champs dans la nouvelle instance et les renvoie. Classe d'objet fournit un clone méthode et fournit un support pour la copie superficielle.
enter image description here

Copie profonde:
Une copie profonde se produit lorsque 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. Non seulement a obj1 été copié, mais les objets qu'il contient ont également été copiés. On peut utiliser Java Object Serialization faire une copie profonde. Malheureusement, cette approche a aussi quelques problèmes (exemples détaillés).
enter image description here

Problèmes possibles:
clone est difficile à mettre en œuvre correctement.
Il vaut mieux utiliser Copie défensive, copier des constructeurs(comme réponse @egaga) ou méthodes d'usine statiques.

  1. Si vous avez un objet, que vous connaissez a un public clone() méthode, mais vous ne connaissez pas le type de l'objet au moment de la compilation, 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 passer outre avec une méthode publique pour qu'il soit accessible.
  2. Un autre problème se pose lorsque nous essayons copie en profondeur d'un objet complexe. Supposons que le clone() La méthode de toutes les variables d'un objet membre fait aussi une copie profonde, c'est trop risqué d'une hypothèse. Vous devez contrôler le code dans toutes les classes.

Par exemple org.apache.commons.lang.SerializationUtils aura la méthode pour le clonage profond en utilisant la sérialisation (La source). Si nous avons besoin de cloner Bean, il y a quelques méthodes utilitaires org.apache.commons.beanutils (La source).

  • cloneBean Clone un bean basé sur les accesseurs et les setters de propriété disponibles, même si la classe de bean elle-même n'implémente pas Cloneable.
  • copyPropertiesCopiera les valeurs de propriété du bean d'origine vers le bean de destination pour tous les cas où les noms de propriété sont les mêmes.

352
2018-03-23 05:47



Suivez juste comme ci-dessous:

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 où vous voulez obtenir un autre objet, effectuez simplement le clonage. par exemple:

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

92
2018-05-17 09:27



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

91
2018-05-02 19:45



Pourquoi n'y a-t-il pas de réponse à l'utilisation de l'API Reflection?

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 vraiment simple.

EDIT: Inclure l'objet enfant 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
2017-08-16 09:27



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

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

  • il ne copiera pas de tableaux de types disparates

  • les tableaux et les listes doivent être tapés ou ils ne trouveront pas la classe à instancier

  • vous devrez peut-être encapsuler des chaînes dans une classe que vous vous déclarez

J'utilise également cette classe pour enregistrer les préférences utilisateur, les fenêtres et autres éléments à recharger lors de l'exécution. C'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
2017-07-09 20:14



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.

Reportez-vous ici: Copie d'objet


21
2018-05-15 14:36



Oui. Tu dois Copie profonde votre objet.


12
2018-05-15 14:35



Ajouter Cloneable et ci-dessous le code de votre classe

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

Utilisez ceci clonedObject = (YourClass) yourClassObject.clone();


12
2017-07-31 15:00



Voici une explication décente de clone() si vous en avez besoin ...

Ici: clone (méthode Java)


9
2018-05-15 14:35