web-dev-qa-db-fra.com

Création d'une méthode hashCode () - Java

J'ai quelques difficultés à écrire une méthode hashCode() pour une classe que j'ai créée. Cette classe est destinée à être utilisée dans un TreeSet et implémente donc Comparable. La classe a les variables suivantes:

public class Node implements Comparable<Node> {
   Matrix matrix;
   int[] coordinates= new int[2];
   Node father;
   int depth;
   int cost;

Voici l'implémentation de la méthode compareTo(). Je veux que la TreeSet organise ces structures de nœud en fonction de leur coût. Par conséquent, compareTo() renvoie le résultat d'une simple soustraction.

public int compareTo(Node nodeToCompare) {
    return this.cost - nodeToCompare.cost;
}

J'ai également implémenté une méthode equals().

public boolean equals(Object objectToCompare) {
    if(objectToCompare== this) {return true;}
    if(objectToCompare== null || objectToCompare.getClass()!= this.getClass()) {return false;}

    Node objectNode= (Node) objectToCompare;
    return this.father.equals(objectNode.father) &&
            this.depth== objectNode.depth &&
            this.cost== objectNode.cost &&
            this.matrix.equals(objectNode.matrix) &&
            Arrays.equals(this.coordinates, objectNode.coordinates);
}

Cela dit, j'ai quelques questions à poser:

  1. Depuis que j'ai implémenté une nouvelle méthode equals(), dois-je implémenter une nouvelle méthode hashCode()?
  2. Comment puis-je implémenter un nouveau hashCode method() avec ces variables? (Notez que la variable matrice du type Matrix a une méthode hashCode() implémentée)

C'est tout!

17
Gonçalo Lourenço

Votre méthode compareTo n'est pas compatible avec votre méthode equals: votre méthode compareTo indique que deux instances sont équivalentes si elles ont le même cost - de sorte qu'un TreeSet ne peut jamais contenir au plus une instance avec un cost donné - mais votre méthode equals ne peut jamais contenir qu'au plus ils ne sont équivalents que s'ils ont la même cost et sont les mêmes de diverses manières.

Donc, en supposant que votre méthode equals soit correcte:

  • vous devez corriger votre méthode compareTo pour être cohérent avec elle.
  • vous devez créer une méthode hashCode qui lui soit cohérente. Je recommande d'utiliser le même type de logique que celui utilisé par Java.util.List.hashCode() , qui est un moyen simple et efficace d'assembler les codes de hachage des objets composants dans un ordre spécifique; fondamentalement, vous écririez quelque chose comme: 
    int hashCode = 1; 
     hashCode = 31 * hashCode + (père == null? 0: father.hashCode ()); 
     hashCode = 31 * hashCode + profondeur; 
     hashCode = 31 * hashCode + cost; 
     HashCode = 31 * hashCode + matrix.hashCode (); 
     HashCode = 31 * hashCode + Java.util.Arrays.hashCode (coordonnées); 
     retourne hashCode;
21
ruakh

Intellij IDEA peut le faire en tant que fonction "clic droit". Le fait de le faire correctement vous en apprendra beaucoup.

Et vous devriez outrepasser les deux dans tous les cas.

8
sethcall

Le contrat pour la méthode hashCode stipule que si deux objets sont égaux, l'appel de hashCode () devrait vous donner le même résultat entier. L’inverse ne doit pas nécessairement être vrai, c’est-à-dire que si deux hashCodes sont identiques, les objets ne doivent pas s’égaler.

En examinant votre méthode equals (qui nécessite une traduction de variable btw), vous pouvez ajouter les hashCodes de toutes les variables de membre interne devant être égales pour que votre méthode equals donne true. par exemple.

public int hashCode() {
    return this.matrix.hashCode() + 
           this.coordinates[0] + 
           this.coordinates[1] + 
           this.father.hashCode() +
           this.depth + this.cost;               
}

Ce qui précède suppose que la matrice et le père ne sont jamais nuls, vous devez vous assurer de vérifier les nuls si ce n'est pas le cas.

Si vous vous sentez plus aventureux, vous pouvez multiplier quelques-uns de ce qui précède par un nombre premier pour éviter les collisions hashCode avec différentes données (cela vous aidera à améliorer les performances si vous utilisez votre classe dans hashTables et hashMaps). Si vous devez prendre en charge les valeurs NULL, la méthode ci-dessus peut être écrite un peu mieux comme ceci:

public int hashCode() {
    return ((this.matrix == null) ? 0 : this.matrix.hashCode()) + 
           17 * this.coordinates[0] + 
           this.coordinates[1] + 
           ((this.father == null) ? 0 : this.father.hashCode()) +
           31 * this.depth + 19 * this.cost;               
}
3
ksymeon

Si votre collection est petite, vous pouvez renvoyer une constante de la méthode hashCode. Il utilise pour trouver rapidement. hashCodes est comme les boîtes, qui conservent des éléments. Les règles sont:

  1. Les éléments égaux doivent être dans la même boîte (ont le même hashCode) - sûrement;
  2. Les éléments non égaux peuvent être dans des zones identiques ou différentes.

Ensuite, vous retournez constant, vous obéissez à ces 2 règles, mais cela peut réduire considérablement les performances sur les petites listes (car JVM recherchera dans tous les éléments, et pas uniquement dans la même boîte). Mais le retour constant est la mauvaise approche.

PS: Désolé pour mon écriture. L'anglais n'est pas ma langue maternelle.

PPS: normalement, vous devez implémenter la méthode hashCode de la même manière qu'égal (utilise les mêmes éléments)

0
MikhailSP