2013-07-10 7 views
2

Quelqu'un peut-il me dire ce qui ne va pas dans ce morceau de code? Je tire mes cheveux!ConcurrentHashMap - comportement impair

Il n'y a pas de problème si j'utilise HashMap au lieu de ConcurrentHashMap. Le code est compilé avec JDK 5,0

public class MapTest { 
    public Map<DummyKey, DummyValue> testMap = new ConcurrentHashMap<DummyKey, DummyValue>(); 

    public MapTest() { 
     DummyKey k1 = new DummyKey("A"); 
     DummyValue v1 = new DummyValue("1"); 
     DummyKey k2 = new DummyKey("B"); 
     DummyValue v2 = new DummyValue("2"); 

     testMap.put(k1, v1); 
     testMap.put(k2, v2); 
    } 

    public void printMap() { 
     for(DummyKey key : testMap.keySet()){ 
      System.out.println(key.getKeyName()); 
      DummyValue val = testMap.get(key); 
      System.out.println(val.getValue()); 
     } 
    } 

    public static void main(String[] args){ 
     MapTest main = new MapTest(); 
     main.printMap(); 
    } 


    private static class DummyKey { 
     private String keyName = ""; 

     public DummyKey(String keyName){ 
     this.keyName = keyName; 
     } 

     public String getKeyName() { 
     return keyName; 
     } 

     @Override 
     public int hashCode() { 
     return keyName.hashCode(); 
     } 

    @Override 
     public boolean equals(Object o) { 
     return keyName.equals(o); 
     } 
    } 

    private static class DummyValue { 
     private String value = ""; 

     public DummyValue(String value){ 
     this.value = value; 
     } 

     public String getValue() { 
     return value; 
     } 
    } 
} 

Ceci est la sortie:

B 
Exception in thread "main" java.lang.NullPointerException 
at test.MapTest.printMap(MapTest.java:27) 
at test.MapTest.main(MapTest.java:34) 
+2

ce qui est à la ligne 27 – stinepike

+0

Meh, je proposerez en ligne 27:. System.out.println (val.getValue()); – happybuddha

Répondre

7

DummyKey.equals implémentation de la méthode est incorrecte, en raison de cette testMap.get(key) retourne toujours nulle. Essayez cette

public boolean equals(Object o) { 
    if (o instanceof DummyKey) { 
     DummyKey other = (DummyKey) o; 
     return keyName == null ? other.keyName == null : keyName.equals(other.keyName); 
    } 
    return false; 
} 

hashCode aussi besoin d'un peu de changement pour être compatible avec des égaux

public int hashCode() { 
    return keyName == null ? 0 : keyName.hashCode(); 
} 
+0

L'ancienne version de DummyKey équals retournera false lors de la comparaison d'un objet à lui-même, ce qui brise le contrat d'égalité d'une manière qui empêchera HashMap de trouver une clé qui a été placée dans la carte. –

+0

Droit! Le code pas très intelligent n'est pas? – TommyQ

+0

Veuillez noter que vous devriez également changer hashCode pour compter aussi pour les valeurs nulles. Le hashCode en cours peut provoquer NullPointerException – Multithreader

1

Le problème vient de votre equals dans DummyKey.

Lorsque vous appelez DummyValue val = testMap.get(key);, la fonction hashcode trouve une correspondance (deux keyname de k1 et key sont les mêmes et sont donc leur hashcode). Est égal à renvoie false car k1.keyname est égal à "A" qui n'est pas égal à key lui-même, qui est en fait de type DummyValue: vous ne comparez pas correctement!

, vous devez donc modifier votre fonction equals:

@Override 
public boolean equals(Object obj) { 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 
    DummyKey other = (DummyKey) obj; 
    if (keyName == null) { 
     if (other.keyName != null) 
      return false; 
    } else if (!keyName.equals(other.keyName)) 
     return false; 
    return true; 
} 
1

S'il vous plaît noter que si vous changez hashCode(), alors vous devez changer equals() ainsi. Sinon, vous rencontrerez des problèmes. Si equals() renvoie true pour deux éléments, alors leur valeur hashCode() doit être égale! Le contraire n'est pas requis mais préférable pour une meilleure performance de hachage. Voici une implémentation de equals() et hashCode(). ASTUCE: si vous utilisez eclipse, vous pouvez utiliser sa fonction de génération de source pour créer la bonne méthode hashCode() et equals() pour vous. La seule chose que vous devez faire est de choisir les variables d'instance qui identifient l'objet. Pour ce faire en éclipse, alors que votre code source est ouvert, consultez les onglets en haut et choisissez « source », puis choisissez « Générer hashCode() et equals() ... »

@Override 
    public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + ((keyName == null) ? 0 : keyName.hashCode()); 

    return result; 
    } 

    Override 
    public boolean equals(Object other) { 
    if(this == other) return true; //for optimization 
    if(! other instanceof this) return false; //also covers for when other == null 
    return this.keyName == null ? other.keyName == null : this.keyName.equals(other.keyName); 
    } 
1

Comme d'autres ont pointé, le problème réside dans la façon dont vous remplacez hashcode et égaux. Deux options: 1) Il suffit de retirer le code et équivaut à 2) Je laisse eclipse générer la source pour hashcode et est égal et cela fonctionne bien. C'est ce que mon éclipse ceinturée pour moi:

@Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result 
       + ((keyName == null) ? 0 : keyName.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     DummyKey other = (DummyKey) obj; 
     if (keyName == null) { 
      if (other.keyName != null) 
       return false; 
     } else if (!keyName.equals(other.keyName)) 
      return false; 
     return true; 
    }