2009-04-13 10 views
39

Ceci est étrange. Un collègue a posé des questions sur l'implémentation de myArray.hashCode() dans java. Je pensais que je savais mais ensuite j'ai fait quelques tests. Vérifiez le code ci-dessous. L'étrange pense que j'ai remarqué est que quand j'ai écrit le premier système, les résultats étaient différents. Notez que c'est presque comme si cela rapportait une adresse de mémoire et que la modification de la classe avait déplacé l'adresse ou quelque chose. Je pensais juste partager.Java Array HashCode implémentation

int[] foo = new int[100000]; 
java.util.Random rand = new java.util.Random(); 

for(int a = 0; a < foo.length; a++) foo[a] = rand.nextInt(); 

int[] bar = new int[100000]; 
int[] baz = new int[100000]; 
int[] bax = new int[100000]; 
for(int a = 0; a < foo.length; a++) bar[a] = baz[a] = bax[a] = foo[a]; 

System.out.println(foo.hashCode() + " ----- " + bar.hashCode() + " ----- " + baz.hashCode() + " ----- " + bax.hashCode()); 

// returns 4097744 ----- 328041 ----- 2083945 ----- 2438296 
// Consistently unless you modify the class. Very weird 
// Before adding the comments below it returned this: 
// 4177328 ----- 4097744 ----- 328041 ----- 2083945 


System.out.println("Equal ?? " + 
    (java.util.Arrays.equals(foo, bar) && java.util.Arrays.equals(bar, baz) && 
    java.util.Arrays.equals(baz, bax) && java.util.Arrays.equals(foo, bax))); 

Répondre

77

Le procédé java.lang.ArrayhashCode est héritée de Object, ce qui signifie que le code de hachage dépend de la référence. Pour obtenir le code de hachage en fonction du contenu du tableau, utilisez Arrays.hashCode.

Méfiez-vous bien que ce soit une implémentation de hachage peu profonde. Une implémentation profonde est également présente Arrays.deepHashCode.

+1

Merci pour cette réponse, mais pourquoi java.lang.Array ne remplace pas les méthodes hashCode (et toString) par défaut? Y a-t-il une bonne raison? –

+4

Parce que hashCode doit être rapide pour être utile (car il est principalement utilisé pour empêcher un appel coûteux de .equals), et même un hashCode de faible valeur sur un tableau peut potentiellement être très lent. Un hashCode qui est fondamentalement aléatoire ne fait pas de mal, il ne fournit aucun avantage. Le moindre de deux maux. – Torque

4

Les tableaux utilisent le code de hachage par défaut, qui est basé sur l'emplacement de mémoire (mais il est pas nécessairement l'emplacement de mémoire, car il est seulement une int et toutes les adresses mémoire ne tient pas). Vous pouvez le voir en imprimant également le résultat de System.identityHashCode(foo).

Les tableaux ne sont que equal s'ils sont identiques, tableau identique. Ainsi, les codes de hachage de tableau seront seulement égaux, en général, s'ils sont identiques, tableau identique.

+0

(et les objets sont déplacés en mémoire, et si vous regardez les codes de hachage, ils ne ressemblent généralement pas à des adresses) –

2

L'implémentation par défaut de Object.hashCode() est en effet de renvoyer la valeur du pointeur de l'objet, bien que cela dépende de l'implémentation. Par exemple, une JVM 64 bits peut prendre le pointeur et XOR et les mots de haut et de bas ensemble. Les sous-classes sont encouragées à remplacer ce comportement si cela a du sens. Cependant, cela n'a aucun sens d'effectuer des comparaisons d'égalité sur des tableaux mutables. Si un élément change, alors les deux ne sont plus égaux. Pour conserver l'invariant que le même tableau retournera toujours le même hashCode, quoi qu'il arrive à ses éléments, les tableaux ne remplacent pas le comportement par défaut du hashcode. Notez que java.util.Arrays fournit une implémentation deepHashCode() lorsque le hachage basé sur le contenu du tableau, plutôt que sur l'identité du tableau lui-même, est important.

+1

Les machines virtuelles modernes déplacent les objets dans la mémoire. Une adresse actuelle peut être utilisée comme une graine, mais le résultat doit être stocké. –

+1

Se déplacer en mémoire ne provoque toujours pas la modification du hashCode. –

2

Je suis d'accord avec l'utilisation java.util.Arrays.hashCode (ou l'emballage générique Objects.hashcode goyave google) mais sachez que cela peut causer des problèmes si vous utilisez Terre cuite - voir this link