2009-07-30 27 views
11

Recuerdo eclipse y la idea tiene esta plantilla para crear automáticamente hashCode de un objeto en función de sus atributos.Crear hash desde cadena e int

Una de las estrategias para usar un número y una cadena es algo como esto.

return stringValue.hashCode() + intValue * 32; 

Ooor algo así como eso.

No tengo eclipse ni idea y me gustaría crear esa función.

EDITAR

Sobre la base de las respuestas que crean este mini-clase

class StringInt { 
     private final String s; 
     private final int i; 

     static StringInt valueOf(String string , int value) { 
      return new StringInt(string, value); 
     } 
     private StringInt(String string, int value) { 
      this.s = string; 
      this.i = value; 
     } 
     public boolean equals(Object o) { 
      if(o != null && o instanceof StringInt){ 
       StringInt other = (StringInt) o; 
       return this.s == other.s && this.i == other.i; 
      } 

      return false; 
     } 
     public int hashCode() { 
      return s != null ? s.hashCode() * 37 + i : i; 
     } 
    } 

Esta clase es para ser utilizado como clave para un gran mapa de memoria (> 10 k elementos) no lo hago desea iterarlos cada vez para encontrar si el String y el int son iguales.

Gracias.

ps .. mmh probablemente deberían ser los nombres StringIntKey.

+0

Oscar, creo que es una buena clase. El método hashCode es claro, confiable y eficiente. ¿Qué pasa si evitamos que la cadena sea nula? En tu constructor, lanza un NPE si es nulo. Entonces podrías eliminar esos guardias nulos en iguales y hashCode. Finalmente, tenga a mano una copia de "Java efectivo" para preguntas como estas. Los métodos hashCode creados por Eclipse e IDEA se basan en ese libro. –

+0

En su método equals debería estar comparando el uso de cadenas iguales en lugar de ==. –

Respuesta

8

uso del Apache Commons HashcodeBuilder:

public int hashCode() { 
    new HashCodeBuilder(17, 37). 
      append(myString). 
      append(myInt); 
} 

Enlace aquí: http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html

Y aquí:

http://www.koders.com/java/fidCE4E86F23847AE93909CE105394B668DDB0F491A.aspx

+0

¿Está en línea el código fuente de HashCodeBuilder? ... Lo veré. – OscarRyz

+0

dice: string.hashCode * 37 + intValue !! suficiente para mi !! Gracias – OscarRyz

3

O, si usted no quiere añadir otra biblioteca , haga algo como lo siguiente:

public int hashCode() { 
    StringBuilder builder = new StringBuilder(); 
    builder.append(myString); 
    builder.append(myInteger); 
    return builder.toString().hashCode(); 
} 
+0

¡Doh! .. a veces extraño este tipo de soluciones !! Sí, no quiero agregar otra biblioteca. Gracias por el consejo – OscarRyz

+2

@aperkins: es más simple escribir "return (myString + myInteger) .hashCode()". El compilador de Java compilará esto en la secuencia equivalente de llamadas StringBuilder.append. –

+2

@perkins: otra cosa, si realmente le preocupa la velocidad, este enfoque es significativamente más lento que el cálculo y la combinación de códigos hash de componentes. –

3

Eclipse siempre más o menos la misma función hash, he aquí un ejemplo de una clase con una y String como campos

public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + this.interger; 
     result = prime * result + ((this.string == null) ? 0 : this.string.hashCode()); 
     return result; 
    } 

Siempre recogen 31 como la primera, y luego multiplique por acumulación de funciones hash o el valor si es un primitivo. Algo así no sería difícil de crear como método.

 public int hashCode(Object ... things) { 
     final int prime = 31; 
     int result = 1; 
     for(Object thing : things) { 
      result = prime * result + thing.hashCode(); 
     } 
     return result; 
    } 
0

En respuesta a su más reciente edición, si la velocidad de recuperación es más importante que las preocupaciones de almacenamiento que podrían pre-calcular y almacenar el código hash en la construcción de su clase StringInt. Esto es seguro ya que marcó los campos String y int como final, y también dado que String es inmutable.

Además, puede optimizar su método equals comprobando que el objeto que se está comparando == this antes de hacer una comparación completa. También recomendaría hacer la comparación basada en int más barata primero antes de comparar los campos de cadena.

Otra sugerencia final: puede cambiar el método valueOf(String, int) para construir un StringInt o devolver una instancia creada previamente si ya existe una con los mismos valores String e int.Esto hace que la construcción sea más cara, pero las comparaciones son muy baratas, ya que puede comparar StringInt s usando "==" sabiendo que nunca se crearán dos StringInt s con el mismo valor String y int.

1

Un método de código hash es algo que posiblemente se llame muchas veces, por lo que vale la pena optimizarlo. Si el cálculo es complicado, considere memorizar el valor hash. Además, evite hacer cosas que impliquen más cálculos de los necesarios. (Por ejemplo, la solución StringBuilder pasa la mayor parte del tiempo creando la cadena temporal.)

La otra cosa que quiero señalar es que la calidad del hash es importante. Desea evitar cualquier algoritmo de código hash que asigne muchas claves comunes. Si eso sucede, la búsqueda de la tabla hash ya no puede ser O (1). (En el peor de los casos, será O (N) ... es decir, equivalente a una búsqueda lineal!). Aquí está un ejemplo de una función hash malo:

int hashcode() { 
    int hash = 1; 
    for (int val : this.values) { 
     hash = hash * value; 
    } 
    return hash; 
} 

considere lo que sucede si un elemento de this.values es cero ...

0

También puede utilizar Objects clase de java.util.Objects paquete para obtener rápidamente código hash.

@Override 
public int hashCode() { 
    return Objects.hash(this.string, this.integerValue, this.otherDataTypes); 
}