2010-10-06 17 views
8

A veces necesito implementar un método hashCode() de obj combinando los hashCodes de sus varios miembros de instancia. Por ejemplo, si el obj combinacional tiene miembros a, b, c y, a menudo veo PPL implementarlo como¿Cuál es la forma preferida de implementar hashCode()?


int hashCode(){ 
    return 31 * 31 * a.hashCode() + 31 * b.hashCode() + c.hashCode(); 
} 

dónde viene este número mágico 31 viene? ¿Es la longitud de 4 bytes o solo un número primo?

¿Hay alguna otra forma preferida/estándar de implementar hashCode()?

+0

Similar (pero no necesariamente duplicado): http://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode –

+0

El prime 31 se utiliza en String.hashCode() Esto hace un buen primer puesto ya que no hay muchos caracteres posibles diferentes, sin embargo tiendo a usar primos más grandes. Un buen sitio para primos "interesantes" es http://primes.utm.edu/curios/ –

Respuesta

8

Ver Effective Java's recipe. Es la mejor fuente, sin dudas.

El uso de un número primo es solo para tratar de obtener una distribución razonablemente buena sin conocer el dominio. Tardará un tiempo en desbordarse al mismo valor. El valor 31 es bastante arbitrario si recuerdo correctamente.

Según Bloch (que utiliza 17 como un valor inicial y 37 como el multiplicador constante):

se utiliza un valor inicial diferente de cero (...) por lo que el valor hash se verá afectada por inicial campos cuyo valor hash (...) es cero. Si se usó cero como , el valor inicial (...) no se vería afectado por ninguno de dichos campos iniciales , lo que podría aumentar las colisiones. El valor 17 es arbitrario.
...
Se eligió el multiplicador 37 porque es un primo impar. Si fue par y la multiplicación se desbordó, la información se perdería porque la multiplicación por dos es equivalente a desplazar. Las ventajas de usar un número primo son menos claras que , pero es tradicional usar primos para este propósito.

+0

CW ya que estoy citando descaradamente a Bloch. –

+4

En la segunda edición de Effective Java, Josh Bloch usa 31 en lugar de 37. Explica esa elección: "Una buena propiedad de 31 es que la multiplicación se puede reemplazar por un cambio y una resta para un mejor rendimiento:' 31 * i = = (i << 5) - i'. Las máquinas virtuales modernas hacen este tipo de optimización de forma automática ". – ColinD

2

Uso de HashCodeBuilder Commons Lang:

public int hashCode() { 
    return HashCodeBuilder.reflectionHashCode(this); 
} 

Ver la API de maneras de hacerlo sin necesidad de utilizar la reflexión. Puede decirle qué campos incluir o qué ignorar.

Consulte también EqualsBuilder, para anular un método equals.

6

Una buena opción es el método GuavaObjects.hashCode. Se necesita cualquier número de argumentos y genera un código hash basado en ellas:

@Override public int hashCode() { 
    return Objects.hashCode(a, b, c); 
} 
0

básicamente, su código hash debe consistir en el parámetro clave de su POJO. Un ejemplo está abajo.

public int hashCode() { 
    int hash = 0; 
    if (getRollId() != null) { 
     hash += getRollId().hashCode(); 
    } 
    if (getName() != null) { 
     hash += getName().hashCode(); 
    } 
    return hash == 0 ? System.identityHashCode(this) : hash; 
} 

En el ejemplo anterior, la identificación del rollo y el nombre son el parámetro clave de ese POJO.

Es una buena práctica si agrega solo esos parámetros al método hashCode que agrega en el método Eqauls del mismo POJO.

1

Generar utilizando su IDE.

0

Creo que la siguiente es una buena práctica para escenarios simples: Si su clase contiene miembros readonly, serían buenos candidatos para generar el código hash del objeto. Si su clase, sin embargo, contiene solo los miembros mutantes, podría crear un campo de solo lectura int que obtenga el valor basado en los valores no nulos que se pasen al constructor.

Cuestiones relacionadas