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 :

HashTable : Problème pour récupérer une valeur


Sujet :

Langage Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 91
    Points
    91
    Par défaut HashTable : Problème pour récupérer une valeur
    EDIT: J'ai lu quelque part que HashTable était mal, j'ai donc remplacer par HashMap, le problème reste le même.

    Bonjour à tous,

    Dans le cadre d'un projet, j'utilise une classe possédant plusieurs hashtables.
    Jusqu'ici rien de très compliqué.

    J'ai un objet Position, qui contient deux entier x et y et pour lequel j'ai redéfinit la méthode hashcode().
    Donc, dans une de mes hashtables, la clef est de type Position.

    Le problème, c'est que j'ai l'impression que pour deux Positions avec le même hashcode, je n'atteint pas la même valeur.

    Bon, je ne sais pas si je suis très clair, donc je vais vous mettre un bout de code et son execution pour mieux comprendre le problème.

    Ma fonction qui fait normalement deux lignes mais que je debug à grand coups de println :
    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 modifierCase(Position position, String input)
    	{
    		Case caseAModifier = this.getCase(position.getLibelle());
     
    		Position p;
    		Set<Position> positions = this.cases.keySet();
    		Iterator<Position> iterateur = positions.iterator();
    		while(iterateur.hasNext())
    		{
    			p = iterateur.next();
    			System.out.println("p.hashcode : "+p.hashCode());
    			System.out.println("this.cases.get(p) : "+this.cases.get(p));
    		}
     
    		System.out.println("position.hashCode() : "+position.hashCode());
    		System.out.println("this.cases.get(position) : "+this.cases.get(position));
    		System.out.println("this.cases.containsKey(position) : "+this.cases.containsKey(position));
    		System.out.println("caseAModifier : "+caseAModifier);
    		this.cases.get(position).setInput(input);
    	}
    Et le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    p.hashcode : 2218
    this.cases.get(p) : org.sparksheet.model.formule.Case@e7b241
    position.hashCode() : 2218
    this.cases.get(position) : null
    this.cases.containsKey(position) : false
    caseAModifier : org.sparksheet.model.formule.Case@e7b241
    Donc, ce que je veux montrer par là, c'est que pour deux positions p et position ayant le même hashcode(), dans un cas le get me renvoie une valeur, dans l'autre il ne trouve rien.

    Bon, il y a surement une explication logique, mais pour l'instant je n'en vois pas.

    Merci d'avance

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Difficile a dire avec si peu de code, on ne vois pas vos ajout, ni vos déclarations de type pour la Map (ou table). Avez vous bien redéfinis correctement equals pour vos clés?

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 91
    Points
    91
    Par défaut
    Non, je n'ai pas redéfini les equals.

    La HashMap se sert des equals et pas des hashCode() pour comparer deux clefs ?

    Je l'ai rajouté de cette manière dans la classe position :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    public boolean equals(Position p)
    	{ return (this.hashCode() == p.hashCode());	}
    Pour ce qui est de la classe sur laquelle je travaille, je peux vous mettre plus de code :
    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
     
    public class Feuille 
    {
    	protected HashMap<Position, Case> cases = new HashMap<Position, Case>();
    	protected HashMap<Integer, Ligne> lignes = new HashMap<Integer, Ligne>();
    	protected HashMap<Integer, Colonne> colonnes = new HashMap<Integer, Colonne>();
    	protected HashMap<PositionZone, Zone> zones = new HashMap<PositionZone, Zone>();
     
    	protected void _ajouterCase(Position position, Case c)
    	{
    		this.cases.put(position, c);
     
    		if(!this.lignes.containsKey(position.getY())) this.lignes.put(position.getY(), new Ligne(position.getLibelleLigne(), new ArrayList<Case>()));
    		if(!this.colonnes.containsKey(position.getX())) this.colonnes.put(position.getX(), new Colonne(position.getLibelleColonne(), new ArrayList<Case>()));
     
    		this.lignes.get(position.getY()).ajouterCase(c);
    		this.colonnes.get(position.getX()).ajouterCase(c);
    		System.out.println("Dans ajouterCase : "+this.cases.get(position));
    	}
     
    	public Case getCase(String libelle)
    	{
    		Position position = new Position(libelle);
    		if(!this.cases.containsKey(position)) 
    			this._ajouterCase(position, new Case(libelle));
    		return this.cases.get(position);
    	}
     
    	public void modifierCase(Position position, String input)
    	{
    		Case caseAModifier = this.getCase(position.getLibelle());
     
    		Position p;
    		Set<Position> positions = this.cases.keySet();
    		Iterator<Position> iterateur = positions.iterator();
    		while(iterateur.hasNext())
    		{
    			p = iterateur.next();
    			System.out.println("p.hashcode : "+p.hashCode());
    			System.out.println("this.cases.get(p) : "+this.cases.get(p));
    		}
     
    		System.out.println("position.hashCode() : "+position.hashCode());
    		System.out.println("this.cases.get(position) : "+this.cases.get(position));
    		System.out.println("this.cases.containsKey(position) : "+this.cases.containsKey(position));
    		System.out.println("caseAModifier : "+caseAModifier);
    		this.cases.get(position).setInput(input);
    	}
    }

    Donc, voila l'essentiel. En gros, ma fonction getCase renvoie toujours une case, si elle existe dans les hashmap elle la renvoie, sinon elle la crée.
    A noter que la fonction getCase me renvoie bien l'instance souhaitée. Le problème vient de la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if(!this.cases.containsKey(position)) 
    			this._ajouterCase(position, new Case(libelle));
    qui est toujours executée et qui m'écrase donc à chaque appel la case précedemment créée.


    Je rajoute aussi le code de la classe Position allegée des getteurs :
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
     
    public class Position 
    {
    	public static final String SEPARATEUR = ":";
    	public static final int NOMBRE_CARACTERES = 26;
    	public static Pattern ANALYSEUR = Pattern.compile("([A-Z]+)([0-9]+)");
     
    	private int x;
    	private int y;
     
    	private String libelle;
    	private String libelleLigne;
    	private String libelleColonne;
     
    	public Position(int x, int y) 
    	{
    		this.x = x;
    		this.y = y;
     
    		this.setLibelleColonne();
    		this.setLibelleLigne();
    		this.setLibelle();
    	}
     
    	public Position(String libelle)
    	{
    		this.libelle = libelle;
     
    		Matcher m = ANALYSEUR.matcher(libelle);
    		if(m.matches())
    		{
    			this.x = StringToInt(m.group(1));
    			this.y = Integer.parseInt(m.group(2));
    		}
    		else
    		{
    			this.x = this.y = 0;
    		}
    		this.setLibelleColonne();
    		this.setLibelleLigne();
    	}
     
    	public int hashCode()
    	{ return this.libelle.hashCode(); }
     
    	public boolean equals(Position p)
    	{ return (this.hashCode() == p.hashCode());	}
     
    	private void setLibelleLigne()
    	{ this.libelleLigne = Position.IntToString(this.y)+SEPARATEUR+Position.IntToString(this.y); }
     
    	private void setLibelleColonne()
    	{ this.libelleColonne = String.valueOf(this.x)+SEPARATEUR+String.valueOf(this.x); }
     
    	private void setLibelle()
    	{ this.libelle = Position.IntToString(this.y)+String.valueOf(this.x); }
     
    	private static String IntToString(int i)
    	{
    		String resultat = "";
    		do
    		{
    			resultat += ((char)((i%NOMBRE_CARACTERES)+'A'));
    			i/=NOMBRE_CARACTERES;
    			--i;
    		}
    		while(i>=0);
     
    		StringBuffer inverseur = new StringBuffer(resultat).reverse(); 
     
    		return inverseur.toString();
    	}
     
    	private static int StringToInt(String s)
    	{
    		int resultat=-1;
     
    		for(int i=0; i<s.length(); ++i)
    			resultat+=(s.charAt(i)-'A'+1)*Math.pow(NOMBRE_CARACTERES, s.length()-i-1);
     
    		return resultat;
    	}
    }

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    houla, y a du boulot

    alors d'abord, votre objet Position, pour ce que j'en juge, n'a ni equals, ni hashcode implémenté. Ensuite, comparer les hashcode n'est en général pas suffisant pour garantir un égalité. Il faut donc détailler votre méthode equals.

    Ensuite, la signature doit être boolean equals(Object) et pas equals(Position).

    Donc on devrais avoir qqch du style

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public boolean equals(Object o){
        if (o==null) return false;
        if (o instanceof Position){
            Position p = (Position)o;
            return x == p.x && y== p.y;
        } else
            return false;
    }
    Enfin, votre objet Position est mutable (son contenu peu changer). Les clés d'un HashMap ou d'une hashtable doivent absolument être immutable (cad entre autre, hashcode constant). En résumé donc, pas de setter dessus.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 91
    Points
    91
    Par défaut
    Ok merci beaucoup, le problème venait effectivement de la méthode equals que j'avais naivement implémentée.

    Après, sur le fait que la classe soit mutable, mes "setteurs" sont en private, et appelés uniquement dans le constructeur. Je ne sais pas si ça en fait un objet mutable.

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    tant qu'il change pas, c'est ce qui importe (c'est la définition même de immutable )

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 26/10/2014, 00h44
  2. [DisplayTag] [Débutant] Decorator & JSTL, problème pour récupérer une valeur.
    Par A&N_L dans le forum Taglibs
    Réponses: 6
    Dernier message: 21/07/2010, 18h04
  3. Problème pour récupérer une valeur
    Par matdev62 dans le forum Développement
    Réponses: 3
    Dernier message: 15/09/2009, 15h07
  4. Réponses: 2
    Dernier message: 21/09/2007, 17h27
  5. problème pour récupérer une valeur dans ma bd (débutante)
    Par auryn111 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 26/08/2005, 17h49

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