(l >> 32)^l
es un buen hashcode en la mayoría de los casos; particularmente cuando el largo tiene una distribución uniforme.
Dado que fue la respuesta aceptada, publicaré esto para aclarar algunos de mis comentarios sobre cuándo NO es un buen hashcode por mucho tiempo.
El ejemplo que dio fue una clase Point como esto:
public class Point {
private final long coords; //x in high-bits, y in low
public int getX() {
return (int)(coords >> 32);
}
public int getY() {
return (int)coords;
}
public int hashCode() {
return (int)((coords >> 32)^(coords));
}
}
Puede parecer artificial, pero de vez en cuando tener múltiples "campos" empaquetados en un largo.
Así que el campo coords
representa 32 bits de xy 32 bits de y. ¿Por qué es esto un problema? Bueno, no es si cada uno de xey están distribuidos uniformemente sobre sus respectivos 32 bits. Pero eso es poco probable en la práctica. Lo que es más probable es que X e Y estén delimitados por un número. Digamos 1024 ya que son 2^10. Esto significa que como máximo se establecen las inferiores 10 bits de cada X e Y:
00000000 00000000 000000XX XXXXXXXX 00000000 00000000 000000YY YYYYYYYY
hay 2^20 (1024 * 1024) combinaciones posibles. ¿Pero cuál es la operación que hashCode está haciendo?
00000000 00000000 000000XX XXXXXXXX
^ 00000000 00000000 000000YY YYYYYYYY
-------------------------------------
= 00000000 00000000 000000?? ????????
Hay como máximo 2^10 (1024) posibles valores hashCode ya que sólo los bajos 10 bits nunca pueden ser distinto de cero. La relación de valores hash a valores reales es 1024:(1024*1024)
o 1:1024
. Así que desde el principio hay una probabilidad de 1/1024 de que dos números tengan el mismo hash.
Ahora calculemos la probabilidad de una colisión aplicando matemática del birthday problem. Sea p (n) la probabilidad de que con n valores habrá al menos una colisión. Sabemos que p (1025+) = 1 ya que solo hay 1024 valores.
p(n) = 1 - (n! * (1024 choose n))/1024^n
Esto se resuelve a lo siguiente:
n: p(n)
1: 0.00000
2: 0.00098
3: 0.00293
4: 0.00585
5: 0.00973
6: 0.01457
...
38: 0.50096
...
79: 0.95444
...
148: 0.99999
Con tan sólo 38 artículos, es probable que una colisión. Con 148 artículos, hay un 99.999% de posibilidades de (al menos una) colisión. Con 148 artículos, cada artículo tiene un 7% de probabilidad de colisionar con otro artículo. Con una función de hash adecuada, tomando conocimiento del dominio, estos números podrían bajar fácilmente a 0.
En otras palabras, conocer su dominio y cómo suceden las cosas en la práctica son la clave para hacer un hash de ejecución.Las funciones de la biblioteca intentan hacer el mejor trabajo posible sin saber nada sobre su dominio y, para ser eficaces, suelen confiar en una distribución de datos que no se realizará en la práctica.
btw, incluso si solo desea guardar los 32 bits más bajos, no es necesario el funcionamiento del módulo. Casting a 'int' es suficiente:' int hashCode = (int) id'. – Grodriguez
@Grodriguez lo siento, pero esta respuesta es terrible! hará que muchos objetos tengan el mismo código hash que creará todo tipo de colisiones hash. Siempre quiere códigos hash distribuidos uniformemente. También la respuesta aceptada no es la mejor solución, ya que java 8 presentó una mejor solución. Consulte la respuesta dada por "Nathan", ya que 'Long.hashcode (long)' no crea un nuevo objeto en la pila –
@Neuron Cualquier función hash que mapee un valor de 64 bits en uno de 32 bits causará " muchos objetos tienen el mismo hashcode ". Simplemente no hay forma de evitar eso. Además, no hay garantía de que '(this.longValue()^(this.longValue() >>> 32))' produzca códigos hash más distribuidos uniformemente que solo mantener los 32 bits más bajos del valor. – Grodriguez