49 votes

Quelle est la raison derrière Enum.hashCode ()?

La méthode hashCode() de la classe Enum est définitive et défini en tant que super.hashCode(), ce qui signifie qu'il renvoie un nombre en fonction de l'adresse de l'instance, qui est un nombre aléatoire à partir de programmeurs POV.

En le définissant par exemple, comme en ordinal() ^ getClass().getName().hashCode() serait déterministe à travers les différentes machines virtuelles. Il serait même travailler un peu mieux, depuis le moins de bits significatifs allait "changer autant que possible", par exemple, pour une énumération contenant jusqu'à 16 éléments et d'une table de hachage de taille 16, il n'y aurait certainement pas de collisions (bien sûr, à l'aide d'un EnumMap est mieux, mais parfois pas possible, par exemple, il n'y a pas ConcurrentEnumMap). Avec la définition actuelle, vous n'avez aucune garantie, avez-vous?

Résumé des réponses

À l'aide de Object.hashCode() compare à un meilleur hashCode comme ci-dessus comme suit:

  • PROS
    • simplicité
  • CONTRAS
    • vitesse
    • plus de collisions (quelle que soit la taille d'une table de hachage)
    • le non-déterminisme, qui se propage à d'autres objets, les rendant inutilisables pour
      • simulations déterministes
      • ETag calcul
      • la chasse aux bogues en fonction, par exemple sur un HashSet itération de l'ordre

Je serais personnellement préfèrent le plus beau de hashCode, mais à mon humble avis pas de raison de poids beaucoup, peut-être à l'exception de la vitesse.

Mise à JOUR

J'ai été curieux au sujet de la vitesse et a écrit un test avec de surprenants résultats. Pour le prix d'un seul champ par classe, vous pouvez déterministe code de hachage qui est près de quatre fois plus rapide. Stocker le code de hachage dans chaque domaine serait encore plus rapide, bien que de façon négligeable.

L'explication de la norme de code de hachage n'est pas beaucoup plus rapide, c'est qu'il ne peut pas être l'objet d'adresses comme des objets est déplacé par le GC.

Mise à JOUR 2

Il y a des choses étranges se passe avec l' hashCode de performance en général. Quand je les comprends, il y a toujours la question, pourquoi System.identityHashCode (lecture à partir de l'objet de l'en-tête) est beaucoup plus lent que l'accès à un objet normal champ.

25voto

aioobe Points 158466

La seule raison pour l'utilisation de l'Objet hashCode() et pour la finale, j'imagine, est de me faire poser cette question.

Tout d'abord, vous ne devriez pas compter sur de tels mécanismes pour le partage des objets entre les machines virtuelles. Ce n'est tout simplement pas une prise en charge de cas d'utilisation. Lorsque vous sérialiser / désérialiser vous devez compter sur vos propres mécanismes de comparaison ou seulement de "comparer" les résultats en fonction des objets à l'intérieur de votre propre JVM.

La raison pour laisser les énumérations hashCode être mis en œuvre en tant que Objects code de hachage (basé sur l'identité) c'est parce que, dans un délai d'une JVM, il y aura seulement une seule instance de chaque enum objet. C'est assez pour s'assurer que cette mise en œuvre a un sens et est correct.

On pourrait dire comme "Hey, de la Chaîne et les wrappers pour les primitives (Long, Integer, ...) ont tous bien définis, déterministe, les spécifications de l' hashCode! Pourquoi ne pas les enums l'avoir?", Eh bien, pour commencer, vous pouvez avoir plusieurs distincts chaîne de références, ce qui représente la même chaîne, ce qui signifie que l'utilisation d' super.hashCode serait une erreur, de sorte que ces classes nécessairement besoin de leur propre hashCode implémentations. Pour ces classes de base, il fait sens pour leur permettre d'avoir bien défini déterministe hashCodes.

Pourquoi ont-ils choisi de le résoudre comme cela?

Regardez bien, les exigences de l' hashCode mise en œuvre. La principale préoccupation est de faire en sorte que chaque objet doit retourner un distinctes code de hachage (sauf s'il est égal à un autre objet). L'identité de l'approche fondée sur super efficace et garantit, pendant que votre suggestion n'est pas. Cette exigence est apparemment plus fort que tout "de commodité bonus" sur la détente sur la sérialisation etc.

12voto

JB Nizet Points 250258

Je pense que la raison pour laquelle ils l'ont rendu final est d'éviter les développeurs, en se tirant dans le pied, par la réécriture d'une sous-optimale (ou même erronée) hashCode.

Quant à la composition de mise en œuvre: il n'est pas stable à travers les machines virtuelles, mais il est très rapide, éviter les collisions, et n'a pas besoin d'un champ supplémentaire dans l'enum. Compte tenu de l'normalement petit nombre d'instances d'une classe enum, et de la vitesse de la méthode equals, je ne serais pas surpris si la table de hachage de recherche le temps était plus grand avec votre algorithme qu'avec l'actuel, en raison de sa complexité supplémentaire.

1voto

pnt Points 1314

La JVM applique que pour une constante enum, un seul objet en mémoire. Il n'y a aucun moyen que vous pouvez vous retrouver avec deux types d'instance des objets de la même enum constante au sein d'une seule machine virtuelle, pas de réflexion, pas à travers le réseau via la sérialisation/désérialisation.

Cela étant dit, puisque c'est le seul objet à représenter cette constante, il n'est pas question que son hascode est son adresse depuis aucun autre objet ne peut occuper le même espace d'adressage dans le même temps. Il est garanti pour être unique et "déterministe" (dans le sens que, dans le même VM, dans la mémoire, tous les objets ont la même référence, peu importe ce que c'est).

0voto

Andreas_D Points 64111

Tant que nous ne pouvons pas envoyer un objet enum 1 à une autre machine virtuelle, je ne vois aucune raison d'imposer de telles exigences aux enums (et aux objets en général).


1 Je pensais que c'était assez clair - un objet est une instance d'une classe. Un objet sérialisé est une séquence d'octets, généralement stockée dans un tableau d'octets. Je parlais d'un objet .

0voto

OrangeDog Points 7380

Il n'est pas nécessaire pour les codes de hachage pour être déterministe entre les machines virtuelles et aucun avantage si elles l'étaient. Si vous êtes en s'appuyant sur ce fait, vous l'utilisez mal.

Comme une seule instance de chaque valeur d'enum existe, Object.hashcode() est garanti de ne jamais entrer en collision, est une bonne réutilisation du code et est très rapide.

Si l'égalité est définie par l'identité, alors Object.hashcode() toujours donner le meilleur rendement.

Le déterminisme d'autres codes de hachage est juste un effet secondaire de leur mise en œuvre. Comme leur égalité est généralement définie par des valeurs de champ, le mélange en non-valeurs déterministes serait une perte de temps.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X