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 :

objet "this" mis à jour par une méthode sans raison


Sujet :

Langage Java

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2008
    Messages : 9
    Points : 9
    Points
    9
    Par défaut objet "this" mis à jour par une méthode sans raison
    Bonjour à vous,
    Merci de m'aider à comprendre le problème ci dessous qui me laisse perplexe:

    Le problème est le suivant:
    J'ai une classe nommée Coup déclarée comme ci dessous:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class Coup {
    	Mouvement_unit_pièce mouvement[];
    	Pièce pièce_mvt;
    	Position_damier damier;
    	int nbre_pièces_mangées;  
    	boolean dame;
    Mouvement_unit_pièce est une autre classe définit par ailleurs dans mon programme.
    la classe Coup possède une méthode:

    Coup ajouter_mouvement(Mouvement_unit_pièce nouveau_mouvement)

    Cette méthode a pour objectif de retourner un objet coup dont le tableau mouvement aura été enrichi du "nouveau_mouvement" en paramètre de la méthode.

    Mon problème est que la méthode, non seulement fait ce qui est décrit ci dessus, mais met aussi à jour l'objet "this" auquel s'applique la méthode (ce qui n'est pas du tout l'objectif cherché.

    Ci dessous un exemple d'appel de la méthode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     public static void main(String[] args) 
       {
    ...
     Mouvement_unit_pièce mouv_test_ajout; // mouvement unitaire utilisé dans le test de la méthode d'ajout mouvement
     Coup coup_test_ajout, coup_test_ajout2;// Coups utilisés pour le test de la méthode d'ajout mouvement
    ...
    coup_test_ajout2 = coup_test_ajout.ajouter_mouvement(mouv_test_ajout);
    ...
    }
    Donc, le souçi comme je l'ai dit, c'est que à la sortie de la méthode, non seulement coup_test_ajout2 possède le nouveau mouvement dans son tableau de mouvement , mais aussi coup_test_ajout. Et là, c'est le drame...

    Voici donc ci-dessous la méthode dont je parle:
    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
     
    	Coup ajouter_mouvement(Mouvement_unit_pièce nouveau_mouvement)
    	 {
    		Coup coup_sortie;
    		coup_sortie = new Coup();// Initialisation du coup qu'on renverra en sortie
     
    		coup_sortie.mouvement = new Mouvement_unit_pièce[21];
    		coup_sortie.mouvement = mouvement;
    		coup_sortie.pièce_mvt = pièce_mvt;
    		coup_sortie.damier=damier;
    		coup_sortie.nbre_pièces_mangées = nbre_pièces_mangées;
    		coup_sortie.dame = dame;
     
     		for (int i=1; i<=21; i++) // On parcours la liste des mouvements de this et lorsqu'on tombe sur un null, on y ajoute le mouvement en entrée
    		{
    			if (coup_sortie.mouvement[i]==null)
    			{				coup_sortie.mouvement[i]= new Mouvement_unit_pièce();// on initialise le nouveau mouvement
    	coup_sortie.mouvement[i]= nouveau_mouvement;
     
    // C'est ici que le drame se produit: Ici, sans que je comprenne pourquoi, this.mouvement[i] est aussi mis à jour sans que je ne lui demande rien.
     
                                         break;
    			}
    		}
     
     
    		return coup_sortie;
    	}
    J'éspère avoir été à peu près clair et je vous remercie d'avance de m'aider dans ce problème.

  2. #2
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    11
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 11
    Points : 11
    Points
    11
    Par défaut
    Bonsoir,

    tout d'abord, je te conseille d'aller voir les conventions de nommage, parce que les noms à rallonge avec des "_" dans tous les sens

    Sinon, tu as déjà une erreur dans ton exemple il me semble :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    coup_test_ajout2 = coup_test_ajout.ajouter_mouvement(mouv_test_ajout);
    Tu appliques la méthode ajouter_mouvement à l'objet coup_test_ajout AVANT de le recopier dans coup_test_ajout2, donc oui, forcément, il est modifié


    En effet, pour ne modifier que coup_test_ajout2, il faudrait faire cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    coup_test_ajout2 = coup_test_ajout;
    coup_test_ajout2.ajouter_mouvement(mouv_test_ajout);

  3. #3
    Membre actif

    Étudiant
    Inscrit en
    Mai 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2006
    Messages : 200
    Points : 276
    Points
    276
    Par défaut
    tout d'abord, je te conseille d'aller voir les conventions de nommage, parce que les noms à rallonge avec des "_" dans tous les sens
    +1

    Tu appliques la méthode ajouter_mouvement à l'objet coup_test_ajout AVANT de le recopier dans coup_test_ajout2, donc oui, forcément, il est modifié
    Non.

    Si on regarde la méthode, on s'aperçoit qu'à aucun moment on ne modifie les attribut de this : on travail tout au long de la méthode sur l'objet coup_sortie.

    Je ne vois rien dans cette méthode qui puisse modifier this. Es-tu sûr que ton objet est modifié ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    coup_test_ajout2 = coup_test_ajout.ajouter_mouvement(mouv_test_ajout);
    Remarque :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    coup_sortie.mouvement[i]= new Mouvement_unit_pièce();
    coup_sortie.mouvement[i]= nouveau_mouvement;
    Il est inutile de créer une nouvelle instance si tu lui affectes une valeur juste après.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2008
    Messages : 9
    Points : 9
    Points
    9
    Par défaut quelques infos supplémentaires
    Merci à vous pour vos réponses,
    D'abord, effectivement, je vais essayer d'être un peu moins bavard dans mes noms de variable et classe.
    Pour ce qui de créer une nouvelle instance juste avant de lui affecter une valeur, merci pour l'info: Effectivement, cela marche tout aussi bien sans.

    Pour mon problème de fond voici quelques infos :

    J'ajoute les quelques lignes ci dessous dans la méthode "ajouter_mouvement" afin de lire le mouvement this avant et après la commande que je suspecte.

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
    Coup ajouter_mouvement(Mouvement_unit_pièce nouveau_mouvement)
     {
    		Coup coup_sortie;
    		coup_sortie = new Coup();// Initialisation du coup qu'on renverra en sortie
     
    		coup_sortie.mouvement = new Mouvement_unit_pièce[21];	// On initialise coup avec les données du coup en entrée: this
     
    		coup_sortie.mouvement = mouvement;
    		coup_sortie.pièce_mvt = pièce_mvt;
    		coup_sortie.damier=damier;
    		coup_sortie.nbre_pièces_mangées = nbre_pièces_mangées;
    		coup_sortie.dame = dame;
    		for (int i=1; i<=21; i++) // On parcours la liste des mouvements de this et lorsqu'on tombe sur un null, on y ajoute le mouvement en entrée
    		{
    			if (coup_sortie.mouvement[i]==null)
    			{
    		/*******************************************************************************
                     *****************************test************************************************/	
    		out.println("test d'affichage de this avant affectation coup_sortie.mouvement[i]");//test
     
    		for (int t=1; t<=4; t++)
    		{
    			if (this.mouvement[t]!=null)//test
    			{
    				out.print("test this.mouvement ["+t+"] dans ajouter mouvement");
    				this.mouvement[t].affiche_mvt();//test
    			}	
    		}
     
    		/*******************************************************************************
                     *****************************test**********************************************/
    				coup_sortie.mouvement[i]= nouveau_mouvement;
    		/*******************************************************************************
                     *****************************test************************************************/	
    		out.println("test d'affichage de this après affectation coup_sortie.mouvement[i]");//test
    		for (int t=1; t<=4; t++)
    		{
    			if (this.mouvement[t]!=null)//test
    			{
    				out.print("test this.mouvement ["+t+"] dans ajouter mouvement");
    				this.mouvement[t].affiche_mvt();//test
    			}	
    		}
     
    		/*******************************************************************************
                     *****************************test************************************************/		
     
     
     
    				if (nouveau_mouvement.dégustation==true)   //On ajoute 1 au nombre de pièces mangées dans le coup si dégustation est à true 
    				{
    					coup_sortie.nbre_pièces_mangées+=1;
    				}
    				break;
    			}
    		}
     
     
    		return coup_sortie;
    	}
    J'utilise ici une méthode affiche_mvt qui me permet d'afficher le contenu d'un mouvement (sa partie essentielle au moins).

    Le résultat obtenu est celui ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    test d'affichage de this avant affectation coup_sortie.mouvement[i]
    test d'affichage de this après affectation coup_sortie.mouvement[i]
    test this.mouvement [1] dans ajouter mouvementPièce blanc (6,7) va de 33 à 11 Mange :false
    Avant l'ajout "nouveau_mouvement" au tableau "coup_sortie.mouvement[i]", le tableau this.mouvement[] est vide. Après l'ajout, il y a une valeur this.mouvement [1]. Donc, c'est bien ici que se pose le problème.

    Etrange non???

  5. #5
    Membre actif

    Étudiant
    Inscrit en
    Mai 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2006
    Messages : 200
    Points : 276
    Points
    276
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    coup_sortie.mouvement = new Mouvement_unit_pièce[21];
    coup_sortie.mouvement = mouvement;
    C'est quoi ça ???


    Tu crées un nouveau tableau puis après tu lui affectes le tableau de this. Voilà pourquoi this est modifié.

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2008
    Messages : 9
    Points : 9
    Points
    9
    Par défaut
    Bonsoir floflo,
    Merci de t'intéresser à mon cas.
    Code :
    coup_sortie.mouvement = new Mouvement_unit_pièce[21];
    coup_sortie.mouvement = mouvement;C'est quoi ça ???


    Tu crées un nouveau tableau puis après tu lui affectes le tableau de this. Voilà pourquoi this est modifié.
    Pour le coup du création d'un nouveau tableau puis affectation d'une valeur, je pense que c'est un peu dans la même veine que ce que tu m'as fait remarquer auparavent. Je n'ai pas bien eu le temps de tout remettre en ordre... Cependant, petite question à ce sujet: Si je met directement coup_sortie.mouvement = mouvement; est-ce que la taille du tableau coup_sortie.mouvement sera la me^me que celle de this.mouvement (à savoir 21)?

    Pour le coup_sortie.mouvement = mouvement;C'est quoi ça ???
    C'est simplement qu'au début de la méthode, j'initialise les mouvements de this vers coup_sortie. Après cela, je rajoute le nouveau_mouvement en paramètre à coup_sortie. A priori, je ne pense pas que cela ait un impact sur this, ou alors, il y a une logique de plus que je n'ai pas bien comprise dans Java...

  7. #7
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut
    Bonjour,
    J'prends la discution en cours, j'espère ne pas être hors sujet...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    coup_sortie.mouvement = new Mouvement_unit_pièce[21];
    coup_sortie.mouvement = mouvement;
    Ces lignes de code signifient que tes 2 références coup_sortie.mouvement ET mouvement pointent vers le même tableau. Il n'y a pas de copie de valeur, il s'agit de références.

    Ce qui fait que lorsque tu modifies une valeur référencée par coup_sortie.mouvement, tu modifies aussi mouvement.

    Voilà un bout de code qui devrait t'aider à comprendre.

    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
    package toto;
     
    public class Application {
     
    	public static void main(String[] args) {
     
    		// On crée un premier tableau référence
    		String strings[] = new String[2];
    		strings[0] = "1";
    		strings[1] = "2";
     
    		// On crée un second tableau en copiant les éléments
    		String strings2[] = new String[strings.length];
    		// On utilise la copie, nous avons donc 2 instances différentes
    		System.arraycopy(strings, 0, strings2, 0, strings.length);
     
    		// On crée un troisième tableau en copiant la référence du second
    		String strings3[] = strings2;
     
    		System.err.println("On affiche AVANT modification du second tableau");
    		System.err.println("1 =  " + strings[0] + " " + strings[1]);
    		System.err.println("2 =  " + strings2[0] + " " + strings2[1]);
    		System.err.println("3 =  " + strings3[0] + " " + strings3[1]);
     
    		System.err.println("On affiche APRES modification du second tableau");
    // On modifie seulement le second tableau
    		strings2[0] = "3";
    		strings2[1] = "4";
    		System.err.println("1 =  " + strings[0] + " " + strings[1]);
    		System.err.println("2 =  " + strings2[0] + " " + strings2[1]);
    		System.err.println("3 =  " + strings3[0] + " " + strings3[1]);
     
    	}
     
    }
    Résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    On affiche AVANT modification du second tableau
    1 =  1 2
    2 =  1 2
    3 =  1 2
    On affiche APRES modification du second tableau
    1 =  1 2
    2 =  3 4
    3 =  3 4
    Tu peux donc remarquer que le troisième tableau a aussi été modifié car il référence le même tableau que le second.
    Le premier tableau lui n'a pas bougé car ses valeurs ont été copiées du tableau 1 vers le tableau 2.

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2008
    Messages : 9
    Points : 9
    Points
    9
    Par défaut Merci beaucoup
    Eh bien merci beaucoup Vincent pour cette explication très claire. Merci aussi floflo: Je pense que c'est ce que tu as tenté de m'expliquer, mais à vrai dire je ne l'avais pas compris car je ne connaissais pas cette notion de copie de référence. Maintenant, je pense que j'ai bien compris. Il me reste plus qu'à aller trouver de la doc pour savoir comment copier par référence et comment copier par valeur.
    En tous cas, j'ai corrigé mon problème en créant un nouveau constructeur de ma classe Coup:
    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 Coup (Coup coup) // Constructeur de Coup par recopie d'un autre coup.
    	{
    		this.mouvement = new Mouvement_unit_pièce[21];
    		int i=1;
    		while (coup.mouvement[i]!=null)
    		{
    			this.mouvement[i] = coup.mouvement[i];
    			i+=1;
    		}
    		this.pièce_mvt=coup.pièce_mvt;
    		this.damier=coup.damier;
    		this.nbre_pièces_mangées = coup.nbre_pièces_mangées;
    		this.dame = coup.dame;
    	}
    Et dans ma méthode d'ajout de mouvement, j'initialise coup_sortie en faisant appel à ce constructeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    coup_sortie = new Coup(this); // Initialisation du coup qu'on renverra en sortie
    Encore merci pour ces explications. La seule chose qui m'inquiète, c'est que j'ai dû faire la même erreur à beaucoup d'endroit...

  9. #9
    Membre actif Avatar de vincent63
    Inscrit en
    Octobre 2005
    Messages
    198
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 198
    Points : 205
    Points
    205
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    coup_sortie = new Coup(this); // Initialisation du coup qu'on renverra en sortie
    Puis que tu es déjà dans ta classe Coup, plutôt que d'utiliser un constructeur, utilise plutôt la méthode clone.

    Pour cela, il faut que tu la redéfinisses . Son contenu sera exactement celui de ton constructeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (coup.mouvement[i]!=null)
                    {
                            this.mouvement[i] = coup.mouvement[i];
                            i+=1;
                    }
    Je n'ai pas tester, mais il me semble qu'il y a quelque chose de curieux dans ce bout de code.
    A ton avis, que se passerait-il si ton tableau fait 20 en taille et que tu aies par exemple coup.mouvement[5] qui soit null, et coup.mouvement[6] différent de null?

    Fonctionnellement, cet exemple n'a peut-être aucune raison d'être, mais si cela arrive, alors ton nouveau tableau ne serait initialisé que pour les 4 permières valeurs.

    A ta place, j'utiliserai plutôt une boucle sur la taille complète du tableau, un bon vieux
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (int i + 0; i< taille; i++)

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

Discussions similaires

  1. Réponses: 7
    Dernier message: 18/09/2010, 01h50
  2. Réponses: 3
    Dernier message: 07/05/2008, 14h53
  3. [SwingWorker] Arret d'une méthode sans raisons..
    Par Invité dans le forum Général Java
    Réponses: 2
    Dernier message: 14/02/2008, 17h34

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