Comment hashCode () est-il calculé en Java?

Quelle est la valeur hashCode() méthode hashCode() dans Java?

J’ai lu que c’est une référence mémoire d’un object … Lorsque j’imprime une valeur de hachage pour un new Integer(1) c’est 1; pour Ssortingng("a") est 97.

Je suis confus: est-ce ASCII ou quel type de valeur est?

Un hashcode est une valeur entière qui représente l’état de l’object sur lequel il a été appelé. C’est pourquoi un Integer qui est défini sur 1 renverra un code de hachage de “1” car Integer's code Integer's hachage d’un Integer's et sa valeur sont identiques. Le code de hachage d’un caractère est égal à son code de caractère ASCII. Si vous écrivez un type personnalisé, vous êtes responsable de la création d’une bonne implémentation hashCode qui représentera le mieux l’état de l’instance actuelle.

La valeur renvoyée par hashCode() n’est en aucun cas la garantie de l’adresse mémoire de l’object. Je ne suis pas sûr de l’implémentation dans la classe Object , mais gardez à l’esprit que la plupart des classes remplaceront hashCode() telle sorte que deux instances sémantiquement équivalentes (mais ne sont pas la même instance) auront la même valeur. Ceci est particulièrement important si les classes peuvent être utilisées dans une autre structure de données, telle que Set, qui repose sur la cohérence du hashCode avec les equals .

Il n’y a pas de hashCode() qui identifie de manière unique une instance d’un object, peu importe quoi. Si vous voulez un code de hachage basé sur le pointeur sous-jacent (par exemple, dans l’implémentation de Sun), utilisez System.identityHashCode() – cela déléguera à la méthode hashCode par défaut qu’elle ait été remplacée ou non.

Néanmoins, même System.identityHashCode() peut renvoyer le même hachage pour plusieurs objects. Voir les commentaires pour une explication, mais voici un exemple de programme qui génère continuellement des objects jusqu’à ce qu’il en trouve deux avec le même System.identityHashCode() . Lorsque je l’exécute, il trouve rapidement deux System.identityHashCode() correspondant en moyenne après avoir ajouté environ 86 000 objects Long wrapper (et Integer wrappers pour la clé) à une map.

 public static void main(Ssortingng[] args) { Map map = new HashMap<>(); Random generator = new Random(); Collection counts = new LinkedList<>(); Long object = generator.nextLong(); // We use the identityHashCode as the key into the map // This makes it easier to check if any other objects // have the same key. int hash = System.identityHashCode(object); while (!map.containsKey(hash)) { map.put(hash, object); object = generator.nextLong(); hash = System.identityHashCode(object); } System.out.println("Identical maps for size: " + map.size()); System.out.println("First object value: " + object); System.out.println("Second object value: " + map.get(hash)); System.out.println("First object identityHash: " + System.identityHashCode(object)); System.out.println("Second object identityHash: " + System.identityHashCode(map.get(hash))); } 

Exemple de sortie:

 Identical maps for size: 105822 First object value: 7446391633043190962 Second object value: -8143651927768852586 First object identityHash: 2134400190 Second object identityHash: 2134400190 

Si vous voulez savoir comment ils sont implémentés, je vous suggère de lire la source. Si vous utilisez un IDE, vous pouvez simplement + sur une méthode qui vous intéresse et voir comment une méthode est implémentée. Si vous ne pouvez pas faire cela, vous pouvez google pour la source.

Par exemple, Integer.hashCode () est implémenté comme

  public int hashCode() { return value; } 

et Ssortingng.hashCode ()

  public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; } 

La hashCode() est souvent utilisée pour identifier un object. Je pense que l’implémentation Object retourne le pointeur (pas un vrai pointeur mais un identifiant unique ou quelque chose comme ça) de l’object. Mais la plupart des classes remplacent la méthode. Comme la classe Ssortingng . Deux objects Ssortingng n’ont pas le même pointeur mais ils sont égaux:

 new Ssortingng("a").hashCode() == new Ssortingng("a").hashCode() 

Je pense que l’utilisation la plus courante de hashCode() est dans Hashtable , HashSet , etc.

Objet API Java hashCode ()

Edit: (dû à un récent downvote et basé sur un article que j’ai lu sur les parameters de la JVM)

Avec le paramètre JVM -XX:hashCode vous pouvez modifier le mode de calcul du hashCode (voir le numéro 222 de la Newsletter des spécialistes Java).

HashCode == 0: renvoie simplement des nombres aléatoires sans relation avec l’endroit où la mémoire a trouvé l’object. Autant que je sache, la lecture-écriture globale de la graine n’est pas optimale pour les systèmes avec beaucoup de processeurs.

HashCode == 1: Compte les valeurs du code de hachage, pas sûr de la valeur de départ, mais cela semble assez élevé.

HashCode == 2: renvoie toujours le même code de hachage d’identité identique à 1. Cela peut être utilisé pour tester le code qui repose sur l’identité de l’object. La raison pour laquelle JavaChampionTest a renvoyé l’URL de Kirk dans l’exemple ci-dessus est que tous les objects renvoyaient le même code de hachage.

HashCode == 3: Compte les valeurs du code de hachage, à partir de zéro. Il ne semble pas être thread-safe, donc plusieurs threads peuvent générer des objects avec le même code de hachage.

HashCode == 4: Cela semble avoir une relation avec l’emplacement de mémoire où l’object a été créé.

HashCode> = 5: Il s’agit de l’algorithme par défaut pour Java 8 et possède une graine par thread. Il utilise le schéma xor-shift de Marsaglia pour produire des nombres pseudo-aléatoires.

J’ai lu que c’est une référence mémoire d’un object.

Non. Object.hashCode() une adresse mémoire il y a environ 14 ans. Pas depuis.

quel type de valeur est

Qu’est-ce que cela dépend entièrement de quelle classe dont vous parlez et si oui ou non il a été remplacé par Object.hashCode ().

Object.hashCode (), si la mémoire sert correctement (vérifiez le JavaDoc pour java.lang.Object), dépend de l’implémentation et changera en fonction de l’object (la machine virtuelle Java dérive la valeur de la valeur de la référence à l’object ).

Notez que si vous implémentez un object non sortingvial et que vous souhaitez les stocker correctement dans un HashMap ou un HashSet, vous DEVEZ substituer hashCode () et est égal à (). hashCode () peut faire ce que vous voulez (c’est entièrement légal, mais sous-optimal pour qu’il retourne 1.), mais il est essentiel que si votre méthode equals () retourne true, la valeur retournée par hashCode () pour les deux objects est égale.

La confusion et le manque de compréhension de hashCode () et equals () sont une source importante de bogues. Assurez-vous de bien vous familiariser avec les JavaDocs pour Object.hashCode () et Object.equals (), et je garantis que le temps passé sera rentabilisé.

 public static int murmur3_32(int paramInt1, char[] paramArrayOfChar, int paramInt2, int paramInt3) { /* 121 */ int i = paramInt1; /* */ /* 123 */ int j = paramInt2; /* 124 */ int k = paramInt3; /* */ /* */ int m; /* 127 */ while (k >= 2) { /* 128 */ m = paramArrayOfChar[(j++)] & 0xFFFF | paramArrayOfChar[(j++)] << '\020'; /* */ /* 130 */ k -= 2; /* */ /* 132 */ m *= -862048943; /* 133 */ m = Integer.rotateLeft(m, 15); /* 134 */ m *= 461845907; /* */ /* 136 */ i ^= m; /* 137 */ i = Integer.rotateLeft(i, 13); /* 138 */ i = i * 5 + -430675100; /* */ } /* */ /* */ /* */ /* 143 */ if (k > 0) { /* 144 */ m = paramArrayOfChar[j]; /* */ /* 146 */ m *= -862048943; /* 147 */ m = Integer.rotateLeft(m, 15); /* 148 */ m *= 461845907; /* 149 */ i ^= m; /* */ } /* */ /* */ /* */ /* 154 */ i ^= paramInt3 * 2; /* */ /* */ /* 157 */ i ^= i >>> 16; /* 158 */ i *= -2048144789; /* 159 */ i ^= i >>> 13; /* 160 */ i *= -1028477387; /* 161 */ i ^= i >>> 16; /* */ /* 163 */ return i; /* */ } 

Si vous êtes vraiment curieux d’apprendre, parcourez ce code disponible dans Hashing.class;

Ici, le premier paramètre HASHING_SEED est calculé en fonction du code ci-dessous

  { long nanos = System.nanoTime(); long now = System.currentTimeMillis(); int SEED_MATERIAL[] = { System.identityHashCode(Ssortingng.class), System.identityHashCode(System.class), (int) (nanos >>> 32), (int) nanos, (int) (now >>> 32), (int) now, (int) (System.nanoTime() >>> 2) }; // Use murmur3 to scramble the seeding material. // Inline implementation to avoid loading classes int h1 = 0; // body for (int k1 : SEED_MATERIAL) { k1 *= 0xcc9e2d51; k1 = (k1 << 15) | (k1 >>> 17); k1 *= 0x1b873593; h1 ^= k1; h1 = (h1 << 13) | (h1 >>> 19); h1 = h1 * 5 + 0xe6546b64; } // tail (always empty, as body is always 32-bit chunks) // finalization h1 ^= SEED_MATERIAL.length * 4; // finalization mix force all bits of a hash block to avalanche h1 ^= h1 >>> 16; h1 *= 0x85ebca6b; h1 ^= h1 >>> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >>> 16; HASHING_SEED = h1; } 

le deuxième paramètre est un tableau de caractères de chaîne, le troisième est toujours “0” et le quasortingème est une longueur de tableau de caractères.

Et le calcul ci-dessus est juste pour le code de hachage Ssortingng.

Pour tout entier, son code de hachage sera sa valeur entière. Pour char (jusqu’à deux lettres), ce sera le code ASCII.

Dans la mesure du possible, la méthode hashCode définie par la classe Object renvoie des entiers distincts pour des objects distincts. (Ceci est généralement implémenté en convertissant l’adresse interne de l’object en un entier, mais cette technique d’implémentation n’est pas requirejse par le langage de programmation Java ™.)

https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode–