2010-04-25 15 views
26

Ok, j'ai entendu de nombreux endroits et sources que chaque fois que je substitue la méthode equals(), j'ai besoin de surcharger la méthode hashCode(). Mais considérez la pièce de code suivantePourquoi devrais-je redéfinir hashCode() lorsque je remplace la méthode equals()?

package test; 

public class MyCustomObject { 

    int intVal1; 
    int intVal2; 

    public MyCustomObject(int val1, int val2){ 
     intVal1 = val1; 
     intVal2 = val2; 
    } 

    public boolean equals(Object obj){ 
     return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
       (((MyCustomObject)obj).intVal2 == this.intVal2); 
    } 

    public static void main(String a[]){ 
     MyCustomObject m1 = new MyCustomObject(3,5); 
     MyCustomObject m2 = new MyCustomObject(3,5); 
     MyCustomObject m3 = new MyCustomObject(4,5); 

     System.out.println(m1.equals(m2)); 
     System.out.println(m1.equals(m3)); 
    } 
} 

Ici, la sortie est vrai, faux exactement la façon dont je veux que ce soit et je ne garde de passer outre la méthode hashCode() du tout. Cela signifie que le remplacement de hashCode() est une option plutôt obligatoire que tout le monde le dit.

Je veux une deuxième confirmation.

+0

duplicata possible de http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c – Oded

+4

Pas un dupe de celui-là; c'est C#, c'est Java. (Le problème est très similaire, peut-être identique, mais quand même.) – Thomas

Répondre

32

Cela fonctionne pour vous parce que votre code n'utilise aucune fonctionnalité (HashMap, HashTable) qui a besoin de l'API hashCode().

Cependant, vous ne savez pas si votre classe (vraisemblablement non écrite à titre exceptionnel) sera appelée ultérieurement dans un code qui utilise effectivement ses objets comme clé de hachage, auquel cas les choses seront affectées.

Selon le documentation for Object class:

Le contrat général de hashCode est:

  • Chaque fois qu'il est invoqué sur le même objet plus d'une fois lors d'une exécution d'une application Java, le hashCode La méthode doit renvoyer systématiquement le même entier, à condition qu'aucune information utilisée dans les comparaisons égales sur l'objet ne soit modifiée. Cet entier n'a pas besoin de rester cohérent d'une exécution d'une application à une autre exécution de la même application.

  • Si deux objets sont égaux selon la méthode égale (Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire le même résultat entier.

+1

Et, facultativement, 'hashCode' doit faire de son mieux pour ne pas retourner le même nombre sur de nombreuses valeurs susceptibles de se produire ensemble lors de la même exécution du programme. J'ai déjà eu un bug de performance qui m'a pris beaucoup de temps pour tracer à l'aide de l'égalité physique avec la fonction de hachage (structurelle) par défaut. Cette utilisation satisfait aux conditions ci-dessus, mais toutes les valeurs physiquement différentes et physiquement différentes ont été hachées dans le même compartiment. –

+0

@Pascal - c'est correct. En effet, le document continue: * Il n'est pas nécessaire que si deux objets sont inégaux selon la méthode equals (java.lang.Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire des résultats entiers distincts. ** Cependant, le programmeur doit savoir que produire des résultats entiers distincts pour des objets inégaux peut améliorer les performances des tables de hachage **. – DVK

+0

"... Autant que cela est raisonnablement pratique, la méthode hashCode définie par la classe Object renvoie des entiers distincts pour des objets distincts (ceci est généralement implémenté en convertissant l'adresse interne de l'objet en entier, mais cette technique d'implémentation n'est pas requis par le langage de programmation Java.) " – DVK

10

Parce que HashMap/Hashtable recherche d'abord l'objet par hashCode().

Si elles ne sont pas identiques, les objets hashmap assert ne sont pas identiques et le retour n'existe pas dans la carte.

5

La raison pour laquelle vous devez @Override ni l'un ni les deux est due à la manière dont ils interagissent avec le reste de l'API.

Vous constaterez que si vous mettez m1 dans un HashSet<MyCustomObject>, alors il n'est pas contains(m2). C'est comportement incohérent et peut causer beaucoup de bugs et de chaos.

La bibliothèque Java a des tonnes de fonctionnalités. Afin de les faire fonctionner pour vous, vous devez jouer par les règles, et en s'assurant que equals et hashCode sont cohérentes est l'un des plus importants.

4

La plupart des autres commentaires que vous avez déjà donné la réponse: vous devez le faire parce qu'il ya des collections (par exemple: HashSet, HashMap) qui utilise hashCode comme exemples d'optimisation à objet « d'index », un ces optimisations s'attendent à ce que: a.equals(b) ==>a.hashCode() == b.hashCode() (NOTE que l'inverse ne tient pas).

Mais comme une information supplémentaire, vous pouvez faire cet exercice:

class Box { 
    private String value; 
    /* some boring setters and getters for value */ 
    public int hashCode() { return value.hashCode(); } 
    public boolean equals(Object obj) { 
      if (obj != null && getClass().equals(obj.getClass()) { 
       return ((Box) obj).value.equals(value); 
      } else { return false; } 
    } 
} 

Le faire:

Set<Box> s = new HashSet<Box>(); 
Box b = new Box(); 
b.setValue("hello"); 
s.add(b); 
s.contains(b); // TRUE 
b.setValue("other"); 
s.contains(b); // FALSE 
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false 

Ce que vous apprenez de cet exemple est que la mise en œuvre equals ou hashCode avec des propriétés qui peuvent être changé (mutable) est une très mauvaise idée.

0

Il est principalement important lors de la recherche d'un objet en utilisant sa valeur hashCode() dans une collection (c'est-à-dire HashMap, HashSet, etc.). Chaque objet renvoie une valeur hashCode() différente. Vous devez donc remplacer cette méthode pour générer systématiquement une valeur hashCode basée sur l'état de l'objet afin d'aider l'algorithme Collections à localiser les valeurs dans la table de hachage.