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

Langage Java Discussion :

Problème copie d'objet


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2008
    Messages : 38
    Par défaut Problème copie d'objet
    Bonjour,

    J'ai le code suivant:

    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
        public void displayLegend() {
            // Affichage de la légende
            Metaphore leg= new Metaphore();
            leg=myTable.getTabMeta()[0];
            int nb = leg.nbForme();
     
            for (int i=0;i<nb;i++)
            {
                leg.getTabForme()[i].setLargeurForme((float)30);
                leg.getTabForme()[i].setTailleMinForme((float)30);
            }
     
     
            legend.actualise(leg.sceneForme(false, true));
        }
    Le problème est que quand je modifie les attributs de leg (dans la boucle for), cela modifie aussi la métaphore issue de myTable.getTabMeta()[0], alors que j'avais crée leg justement dans le but que la métaphore de base ne soit pas affectée par les changement.

    Quelqu'un pourrait m'aider s'il vous plaît?

    Merci

  2. #2
    Membre Expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Par défaut
    Hello,

    il faut faire un clônage en profondeur.

    http://ydisanto.developpez.com/tutor...2se/cloneable/

  3. #3
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Pour que tu comprennes bien:
    leg désigne un objet de type Metaphore. Mais tu n'as qu'un pointeur vers un objet et pas l'objet lui-même.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Métahpore leg; // leg est défini mais il n'y a pas d'objet au bout. leg=null
    leg=new Metaphore(); // leg a un nouvel objet au bout du pointeur (qu'il y ait ou non un objet avant)
    leg=myTable.getTabMeta()[0]; // leg pointe sur un objet déjà existant. tu recopies le pointeur mais pas l'objet !!!
    Quand un objet n'est plus pointé par rien, la mémoire est récupérée par le garbage collector.

    Si tu as compris ces 3 commentaires, tu comprends que dans:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            Metaphore leg= new Metaphore();
            leg=myTable.getTabMeta()[0];
    la partie orange ne sert à rien. Tu définis un pointeur, tu crées un nouvel objet, que tu laisses tomber à la ligne d'après pour un objet déjà existant.

  4. #4
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2008
    Messages : 38
    Par défaut
    OK j'ai bien compris, merci. J'ai donc utilisé clone:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     Metaphore leg= new Metaphore();
            leg=(myTable.getTabMeta()[0].clone());
     
           System.out.println(leg); 
           System.out.println(myTable.getTabMeta()[0]);
    Les adresses sont maintenant bien différentes.

    dans ma classe Metaphore:

    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
    30
    31
    32
    33
    34
    public class Metaphore implements Cloneable{
     
        private final static int NB_FORME_MAX = 100;   //le nombre de forme maximal 
        //dans la metaphore
        //la taille de la metaphore par rapport a la taille de la fenetre3D
        private final static double TAILLE_AFFICHAGE = 0.6d;    //on cree le tableau de forme
        private Forme[] tabForme = new Forme[NB_FORME_MAX];
        private String Nom;
        //Constructeur
        public Metaphore() {
            //on initialise toutes les formes a null
            for (int i = 0; i < NB_FORME_MAX; i++) {
                this.tabForme[i] = null;
            }
        }
     
     //fonctions diverses
     
        @Override
        public Metaphore clone(){
            Metaphore meta=null;
     
            try{
                meta= (Metaphore) super.clone();
     
            }
            catch(CloneNotSupportedException cnse){
                cnse.printStackTrace(System.err);
            }
            meta.tabForme = (Forme[]) tabForme.clone(); //Clonage du tableau de forme puisque c'est ce qui m'interesse
            return meta;
        }
     
    }
    Et dans ma classe Forme :

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class Forme implements Cloneable{
        private String nom;
        private String forme;
        private String couleur;
        private float largeurForme;
        private float tailleForme;
        private float tailleMinForme;
     
        /** Creates a new instance of Forme */
        public Forme() {
        }
     
        public Forme(String nom, String forme, String couleur, float tailleForme, 
                float tailleMinForme, float largeurForme) {
     
            this.nom = nom;
            this.forme = forme;
            this.couleur = couleur;
            this.tailleForme = tailleForme;
            this.tailleMinForme = tailleMinForme;
            this.largeurForme = largeurForme;
        }
     
       //fonctions diverses
     
            @Override
        public Forme[] clone(){
            Forme[] plop=null;
     
            try{
                plop= (Forme []) super.clone();
            }
            catch(CloneNotSupportedException cnse){
                cnse.printStackTrace(System.err);
            }
     
            return plop;
        }
    }
    Voila ce que j'ai fait pourtant quand je modifie mon attribut tailleMinForme dans leg (voir dans mon premier message), ça modifie toujours celui dans myTable.getTabMeta[0].

    Je suppose qu'il doit y avoir une erreur dans mon clonage dans metaphore ou dans forme..

  5. #5
    Membre Expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Par défaut
    Oui, plusieurs erreurs:

    - quand tu clone, cela ne suffit pas d'appeler super.clone. Super.clone fait le travail de clônage des champs nécessaires dans la classe parent, pas dans la classe courante. De plus, l'implémentation de Object#clone ne fait pas grand chose (mise à part instancier le type correct), donc ça sert souvent à rien d'invoquer super.clone(), à moins que tu utilises une hiérarchie d'héritage.
    - clône ne doit jamais retourner un tableau du type courant. C'est une aberration et c'est assez grave (conceptuellement, tu dis à la machine qu'à chaque demande de clône d'un objet, tu renvoies plusieurs clônes: relis comme il faut la description du contrat de clone, notament cette partie:
    Pour un objet "clonable" x :
    l'expression x.clone() != x doit renvoyer true ;

    l'expression x.clone().getClass() == x.getClass() doit renvoyer true (par convention) ;

    l'expression x.clone().equals(x) doit renvoyer true (par convention).

    Par convention, l'objet retourné doit être obtenu par un appel à la méthode super.clone() .
    Si une classe et toutes ses classes parentes (exceptée la classe Object) respectent cette convention, alors l'expression x.clone().getClass() == x.getClass() envoie bien true.
    )
    - tu dois faire un clonage en profondeur (cf mon premier post). Cela veut dire qu'il ne te suffira pas de cloner les collections, mais également leur contenu.

    Un méthode clone correctement implémentée pourrait ressembler à 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
    28
    29
    30
    31
    public class Metaphore implements Cloneable{
        private final static int NB_FORME_MAX = 100;   //le nombre de forme maximal 
        //dans la metaphore
        //la taille de la metaphore par rapport a la taille de la fenetre3D
        private final static double TAILLE_AFFICHAGE = 0.6d;    //on cree le tableau de forme
        private Forme[] tabForme = new Forme[NB_FORME_MAX];
        private String Nom;
        //Constructeur
        public Metaphore() {
            //on initialise toutes les formes a null
            for (int i = 0; i < NB_FORME_MAX; i++) {
                this.tabForme[i] = null;
            }
        }
     
        @Override
        public Metaphore clone(){
      Metaphore clone=(Metaphore)super.clone();
     
      int i=0;
      for(Forme f : tabForme) {
        if(f!=null)
          clone.tabForme[i] = (Forme) f.clone();
        i++;
      }
      clone.Nom = Nom;
     
      return clone;
        }
     
    }
    ça s'appelle un clônage en profondeur (on clône également le contenu des tableaux et des collections, et pas seulement les tableaux ou collections elle-mêmes). Utilisé également lors de copies défensives, afin de protéger les invariants d'une classe


  6. #6
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Avril 2008
    Messages : 38
    Par défaut
    Ok la je comprends mieux

    Donc voila la fonction d'appel
    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
        public void displayLegend() {
            // Affichage de la légende
            Metaphore leg = new Metaphore();
     
            leg = (myTable.getTabMeta()[0].clone());
     
            System.out.println(leg);
            System.out.println(myTable.getTabMeta()[0]);
            // ici les adresses de leg et myTable..getTabMeta()[0] sont bien différentes
     
     
            int nb = leg.nbForme();
     
            for (int i = 0; i < nb; i++) {
                leg.getTabForme()[i].setLargeurForme((float) 30);
                leg.getTabForme()[i].setTailleMinForme((float) 30);
            }
            System.out.println(myTable.getTabMeta()[0].getTabForme()[0].getLargeurForme());
     
            legend.actualise(leg.sceneForme(false, true));
        }
    Ma fonction clone dans la classe métaphore:

    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
        @Override
        public Metaphore clone(){
     
            Metaphore clone=new Metaphore();
            int i = 0;
     
            try {
                clone = (Metaphore) super.clone();
            } catch (CloneNotSupportedException ex) {
               ex.printStackTrace(System.err);
            }
            for (Forme f : tabForme) {
                if (f != null) {
                    clone.tabForme[i] = f.clone();
                }
                i++;
            }
            clone.Nom = Nom;
     
            return clone;
        }
    et le clone de ma classe Forme:
    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
        public Forme clone() {
     
            Forme plop = new Forme();
     
            try {
                plop = (Forme) super.clone();
            } catch (CloneNotSupportedException ex) {
                ex.printStackTrace(System.err);
            }
     
            plop.largeurForme = largeurForme;
            plop.tailleMinForme = tailleMinForme;
            plop.couleur = couleur;
            plop.forme = forme;
            plop.tailleForme =tailleForme;
            plop.nom = nom;
     
            return plop;
        }
    Donc la a priori le clonage fonctionne puisque qd je lance en debugger leg et myTable.getTabMeta()[0] ont bien les mêmes valeurs de champs et une adresse différente.

    Pourtant lorsque je passe sur les instructions:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                leg.getTabForme()[i].setLargeurForme((float) 30);
                leg.getTabForme()[i].setTailleMinForme((float) 30);
    Le programme modifie aussi myTable.TabMeta[0].

    Je comprends pas absolument pourquoi puisque la les adresse des 2 métaphores sont bien différentes

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

Discussions similaires

  1. Problème de copie d'objet
    Par shirya dans le forum VB.NET
    Réponses: 3
    Dernier message: 07/08/2008, 15h43
  2. [FLASH MX] Problème avec l'objet Date
    Par n_tony dans le forum Flash
    Réponses: 13
    Dernier message: 22/03/2005, 13h44
  3. [VB6] Copie d'objet
    Par preverse dans le forum VB 6 et antérieur
    Réponses: 12
    Dernier message: 23/08/2004, 10h04
  4. [VB6] Copie d'objets
    Par austin49 dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 19/05/2003, 18h05

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