IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Collection et Stream Java Discussion :

Problème de copie d'un tableau d'objets


Sujet :

Collection et Stream Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2015
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2015
    Messages : 18
    Par défaut Problème de copie d'un tableau d'objets
    Bonjour,

    je crée des objets (complexes) d'une classe C1 pour les mettre dans deux ArrayList différents AL1 et AL2 (je veux avoir des objets séparés).
    J'applique ensuite des modifications aux objets de AL1, le résultat est que même les objets de AL2 sont modifiés c'est comme si les objets sont les même.
    J'ai consulté le Net, j'ai trouvé que c'était un problème de référence à cause de la copie "superficielle". J'ai alors utilisé Clone comme solution tout en faisant le nécessaire pour mes classes : Clonable et redéfinition de la méthode clone(). Malheureusement, le problème est toujours le même; les objets de AL2 sont modifiés. Je me suis cassé les dents ... mais rien


    Voici mes déclarations de classes et ArrayList :


    Classe 1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class A implements Cloneable{
     
    	private double a1;
    	private int a2 = 1;
     
            //Constructeur 
    	public EnergyProfile (double enerC){
    		this.a1 = enerC;
    	}
     
    	@Override
    	public A clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
    		return new A(a1, a2);
    	}
     
          // Constructeur par défaut  
          ....
     
    }
    Classe 2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class B implements Cloneable {
    	private String b1;
    	private double b2;
     
    	public B(String b1) {
    		this.b1 = b1;
    	}
     
    	@Override
    	public B clone() throws CloneNotSupportedException {
    		return new B(b1, b2);
    	}
     
           // Constructeur par défaut 
          ...
     
    }
    Classe 3
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class C implements Cloneable{
     
    	private int c1;
    	private String c2;
     
    	private A  c3= new A();	
    	private ArrayList<B> c4 = new ArrayList <B> ();
     
    	private double c5= 0;
     
    	public C (int x, String y, A z, ArrayList<B> t) {
    		c1= x;
    		c2= y;
    		c3= z;
    		c4= t;	
    	}
     
    	@Override
    	public C clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
    		return new C(x, y, z.clone(), (ArrayList<B>) t.clone(), u) ;
    	}
     
         // Constructeur par défaut 
           ...
    }
    Classe 4
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class D implements Cloneable{ 
     
    	private int d1;
    	private ArrayList<C> d2 = new ArrayList<C>();
     
    	private C d3;	
    	private ArrayList<Double> d4= new ArrayList<Double>();
     
            // Constructeur 
    	public D(int x, ArrayList<C> y) {
    		d1= x;
    		d2 = y;
                    d3 = new C();    
    		d4= new ArrayList<>();
    	}
     
    	@Override
    	public D clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
     
    		ArrayList<C> copyd2 = new ArrayList<C>();		
    		for (C c : d2) {
    			copyd2.add(c.clone());
    		}	
    		return new D (d1, d2, d3.clone(), (ArrayList<Double>) d4.clone());		
    	}
     
    .....
    }
    Déclaration et remplissage des tableaux d'objets
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    ArrayList<D> AL1= new ArrayList<D>();
     
    ArrayList<D> AL2= new ArrayList<D>();
     
    dElement = new D(.....);
     
    AL1.add(dElement);
     
    try {AL2.add(dElement.clone());
          } catch (CloneNotSupportedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    Modification des objets dans AL1 (aucune modification n'est effectuée sur les objets de AL2).
    ......
     
    Affichage des objets AL2 (ils sont modifiés comme pour les objets de AL1).

    Merci pour votre aide

  2. #2
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    Il faut bien comprendre le concept de reference. Si tu as utilisé des langages comme le C/C++, en java, tous les objets peuvent etre vus comme des pointeurs (sauf que la libération mémoire est gérée automatiquement).

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MaClasse c1 = new MaClass();
    MaClasse c2 = c1; // c1 et c2 pointent sur le meme objet. Ca veut dire que si je modifie l'objet référencé par c1, je modifie l'objet référencé par c2.
    Concernant ce que tu appelles "copie", elle n'a rien de superficielle. C'est juste une référence, pas une copie.

    Pour revenir à ton probleme, clone est bien une solution. Après une lecture un peu en diagonal de ton code, je pense que le probleme vient des arraylist. Une arraylist est un simple tableau d'objets, la cloner ne clone pas les objets qu'elle contient. C'est à mon avis l'origine de ton probleme.

    Cloner une arraylist te permet de pouvoir modifier la liste des elements de celle-ci dans l'un des objets sans impacter la liste dans l'autre (tu peux par exemple vider la liste de l'objet 1 et cela ne changera pas celle de 2). En revanche, si tu modifies les objets contenus dans l'arraylist, ils seront bien modifiés sur les 2 (et je suppose que c'est ca le bug que tu observes).

    Bref, pour conclure, la solution est de cloner non pas l'arraylist mais sont contenu. Ca revient à remplacer (partout ou tu clones les arraylist):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return new C(x, y, z.clone(), (ArrayList<B>) t.clone(), u) ;
    par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ArrayList<B> newList = new ArrayList<B>(t.size());
    for(B b : t)
    {
       newList.add(b.clone());
    }
    return new C(x, y, z.clone(), newList, u) ;
    PS: evite de poster des messages taggés "Urgent", c'est souvent peu apprécié sur les forums. Et tu n'obtiendras pas de réponse plus rapide.

  3. #3
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par hwoarang Voir le message
    Bref, pour conclure, la solution est de cloner non pas l'arraylist mais sont contenu. Ca revient à remplacer (partout ou tu clones les arraylist):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return new C(x, y, z.clone(), (ArrayList<B>) t.clone(), u) ;
    par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ArrayList<B> newList = new ArrayList<B>(t.size());
    for(B b : t)
    {
       newList.add(b.clone());
    }
    return new C(x, y, z.clone(), newList, u) ;
    J'ai un problème avec ce genre de code pour clone(), car il ne respecte pas les conventions de la méthode qui disent que l'instance retourné doit être celle reçu depuis l'appel à super.clone() !
    En effet cela peut "casser" le cloneage pour les éventuelles classes filles...

    Bref il faut toujours appeler super.clone() !

    Cela donnerait quelque chose comme cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    	@Override
    	public C clone() {
    		try {
    			// 1. On appelle la méthode super.clone()
    			// qui se chargera de créer le bon type
    			// et de faire la copie des primitifs/références
    			C copy = (C) super.clone();
     
    			// 2. On clone manuellement les attributs qui doivent l'être
    			// (en général les objets mutables)
    			if (copy.z != null) {
    				copy.z = copy.z.clone();
    			}
    			if (copy.t != null) {
    				copy.t = (ArrayList<B>) copy.t.clone();
    				// On clone tous les éléments de la liste
    				// (ici encore ce n'est utile que s'ils sont mutable) 
    				ListIterator<B> iterator = copy.t.listIterator();
    				while (iterator.hasNext()) {
    					iterator.set(iterator.next().clone());
    				}
    			}
    			return copy;
    		} catch (CloneNotSupportedException e) {
    			throw new IllegalStateException(e);
    		}
    	}

    a++

  4. #4
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    J'ai un problème avec ce genre de code pour clone(), car il ne respecte pas les conventions de la méthode qui disent que l'instance retourné doit être celle reçu depuis l'appel à super.clone() !
    En effet cela peut "casser" le cloneage pour les éventuelles classes filles...

    Bref il faut toujours appeler super.clone() !
    Ah, merci, je ne connaissais pas cette regle (je n'ai jamais eu besoin de clone pour l'instant). Je me suis contenté de reprendre le code posté originalement en clonant les objets mutables.

  5. #5
    Modérateur
    Avatar de kolodz
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    2 209
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 209
    Billets dans le blog
    52
    Par défaut
    On va la faire rapide :

    En premier lieu, merci d'utiliser la balise code !
    En suite, il est préférable que le code que tu fournissent compile. Dans ton cas, il manque un constructeur sur deux !

    Tes erreurs :

    1. Tu utilise le clone de ArrayList qui précisent ceci dans la documentation :
    Citation Envoyé par javadoc
    Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)
    Si tu veux ne pas avoir les mêmes entités, il faut faire une copie profonde. Comme tu l'as réalisé sur certaines listes...

    2. Tu ne vérifie pas la non nullité de tes objets avant de faire tes clones...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public C clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return new C(x, y, z.clone(), (ArrayList<B>) t.clone(), u) ;
    }
    Si tu fait un clone sur un objet C qui a z null ? (Au passage, il n'y a pas de propriété z sur l'objet, mais ça doit être ton code que tu nous à offusqué à l’arrache !)
    Il faudrait donc que tu réalise un test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return new C(x, y, z!= null ? z.clone(): null, (ArrayList<B>) t.clone(), u) ;
    Ici, c'est la version ternaire du test de non nullité.

    Cordialement,
    Patrick Kolodziejczyk.

    source :
    http://docs.oracle.com/javase/7/docs...ml#clone%28%29
    Si une réponse vous a été utile pensez à
    Si vous avez eu la réponse à votre question, marquez votre discussion
    Pensez aux FAQs et aux tutoriels et cours.

  6. #6
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2015
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2015
    Messages : 18
    Par défaut
    Citation Envoyé par saimer Voir le message
    Bonjour,

    je crée des objets (complexes) d'une classe C1 pour les mettre dans deux ArrayList différents AL1 et AL2 (je veux avoir des objets séparés).
    J'applique ensuite des modifications aux objets de AL1, le résultat est que même les objets de AL2 sont modifiés c'est comme si les objets sont les même.
    J'ai consulté le Net, j'ai trouvé que c'était un problème de référence à cause de la copie "superficielle". J'ai alors utilisé Clone comme solution tout en faisant le nécessaire pour mes classes : Clonable et redéfinition de la méthode clone(). Malheureusement, le problème est toujours le même; les objets de AL2 sont modifiés. Je me suis cassé les dents ... mais rien


    Voici mes déclarations de classes et ArrayList :


    Classe 1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class A implements Cloneable{
     
    	private double a1;
    	private int a2 = 1;
     
            //Constructeur 
    	public EnergyProfile (double enerC){
    		this.a1 = enerC;
    	}
     
    	@Override
    	public A clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
    		return new A(a1, a2);
    	}
     
          // Constructeur par défaut  
          ....
     
    }
    Classe 2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class B implements Cloneable {
    	private String b1;
    	private double b2;
     
    	public B(String b1) {
    		this.b1 = b1;
    	}
     
    	@Override
    	public B clone() throws CloneNotSupportedException {
    		return new B(b1, b2);
    	}
     
           // Constructeur par défaut 
          ...
     
    }
    Classe 3
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class C implements Cloneable{
     
    	private int c1;
    	private String c2;
     
    	private A  c3= new A();	
    	private ArrayList<B> c4 = new ArrayList <B> ();
     
    	private double c5= 0;
     
    	public C (int x, String y, A z, ArrayList<B> t) {
    		c1= x;
    		c2= y;
    		c3= z;
    		c4= t;	
    	}
     
    	@Override
    	public C clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
    		return new C(x, y, z.clone(), (ArrayList<B>) t.clone(), u) ;
    	}
     
         // Constructeur par défaut 
           ...
    }
    Classe 4
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class D implements Cloneable{ 
     
    	private int d1;
    	private ArrayList<C> d2 = new ArrayList<C>();
     
    	private C d3;	
    	private ArrayList<Double> d4= new ArrayList<Double>();
     
            // Constructeur 
    	public D(int x, ArrayList<C> y) {
    		d1= x;
    		d2 = y;
                    d3 = new C();    
    		d4= new ArrayList<>();
    	}
     
    	@Override
    	public D clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
     
    		ArrayList<C> copyd2 = new ArrayList<C>();		
    		for (C c : d2) {
    			copyd2.add(c.clone());
    		}	
    		return new D (d1, d2, d3.clone(), (ArrayList<Double>) d4.clone());		
    	}
     
    .....
    }
    Déclaration et remplissage des tableaux d'objets
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    ArrayList<D> AL1= new ArrayList<D>();
     
    ArrayList<D> AL2= new ArrayList<D>();
     
    dElement = new D(.....);
     
    AL1.add(dElement);
     
    try {AL2.add(dElement.clone());
          } catch (CloneNotSupportedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    Modification des objets dans AL1 (aucune modification n'est effectuée sur les objets de AL2).
    ......
     
    Affichage des objets AL2 (ils sont modifiés comme pour les objets de AL1).

    Merci pour votre aide

    MERCI beaucoup hwoarang, ça marche très bien.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2007] Problème de copie ligne dans tableau excel
    Par Marcopololo dans le forum VBA Access
    Réponses: 8
    Dernier message: 10/12/2011, 17h09
  2. Réponses: 4
    Dernier message: 29/06/2007, 11h17
  3. Problème avec un tableau d'objet
    Par tyrant dans le forum Collection et Stream
    Réponses: 5
    Dernier message: 18/11/2006, 19h45
  4. un problème avec un tableau d'objet, erreur bete ?
    Par Heero_2040 dans le forum C++
    Réponses: 12
    Dernier message: 13/07/2006, 13h20
  5. Réponses: 13
    Dernier message: 03/04/2006, 10h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo