2008-10-10 15 views
6

Recientemente surgió un problema interesante. Nos encontramos con algún código que está usando hashCode() como una fuente de sal para el cifrado MD5, pero esto plantea la pregunta: ¿hashCode() devolverá el mismo valor para el mismo objeto en diferentes máquinas virtuales, diferentes versiones de JDK y sistemas operativos? Incluso si no está garantizado, ¿ha cambiado en algún momento hasta ahora?¿Es String.hashCode() portátil entre máquinas virtuales, JDK y sistemas operativos?

EDITAR: me refiero a String.hashCode() en lugar de la más general Object.hashCode(), que por supuesto puede ser anulada.

+0

La pregunta me asusta un poco en realidad. La aleatoriedad es exactamente lo que quieres en una fuente de sal en lugar de una implementación consistente. ¿Por qué no simplemente usar Math.random y almacenar el resultado en alguna parte? – jsight

Respuesta

8

No. Desde http://tecfa.unige.ch/guides/java/langspec-1.0/javalang.doc1.html:

El contrato general de hashCode se como sigue:

  • Cada vez que se invoca en el mismo objeto más de una vez durante una ejecución de una aplicación Java , hashCode debe devolver consistentemente el mismo número entero. El número entero puede ser positivo, negativo o cero. Sin embargo, este entero no tiene que ser consistente desde una aplicación Java a otra, o desde una ejecución de una aplicación a otra ejecución de la misma aplicación. [...]
+1

incorrecto Esto se aplica a java.lang.Object, no a java.lang.String. Esto último restringe aún más la especificación al uso de una implementación específica. – Gili

+0

¿No debería retractarse de su respuesta incorrecta? – missingfaktor

0

me gustaría añadir que se puede anular hashCode() (no se olvide de equals() si lo hace) para asegurarse de que sus objetos de negocio devuelven el mismo código hash de todo el mundo . Esos objetos tendrán al menos un hashCode predecible.

+0

No necesita anular iguales si reemplaza hashCode, aunque no tengo idea de por qué desea hacerlo. –

3

Depende del tipo:

  • Si usted tiene un tipo que no ha anulado hashCode(), entonces probablemente devolverá un código hash diferente() cada vez que se ejecuta el programa.
  • Si tiene un tipo que anula hashCode() pero no documenta cómo se calcula, es perfectamente legítimo que un objeto con la misma información devuelva un hash diferente en cada ejecución, siempre que devuelva el mismo hash para llamadas repetidas dentro de la misma ejecución.
  • Si tiene un tipo que anula hashCode() de manera documentada, es decir, el algoritmo es parte del comportamiento documentado, entonces probablemente esté seguro. (java.lang.String documenta esto, por ejemplo.) Sin embargo, todavía me mantendría alejado de confiando en esto en principio general, personalmente.

Solo una advertencia del mundo de .NET: He visto al menos a algunas personas en un mundo de dolor al usar el resultado de string.GetHashCode() como hash de contraseña en una base de datos. El algoritmo cambió entre .NET 1.1 y 2.0, y de repente todos los hash son "incorrectos". (Jeffrey Richter documenta un caso casi idéntico en CLR a través de C#). Cuando se debe almacenar un hash , prefiero que se calcule de una manera que sea siempre con garantía de estabilidad (p. MD5 o una interfaz personalizada implementada por tus tipos con una garantía de estabilidad.

+0

El punto 3 no es verdadero, la implementación de String.hashCode cambió en java 1.2. http://books.google.com/books?id=ZZOiqZQIbRMC&pg=PA41&lpg=PA41&dq=string+hashcode+pathological+behaviour&source=web&ots=UZM_aodFaZ&sig=TWFCLMcBgy-l10kiWKll1ShfZ_o&hl=en&sa=X&oi=book_result&resnum=1&ct=result –

+0

Dave: en Java 1.1, los documentos no especificaron un algoritmo para String.hashCode, por lo que no era seguro confiar en él, y era aceptable que se cambiara en Java 1.2. El algoritmo ahora está documentado explícitamente, romperlo sería violar el comportamiento documentado. (Continuación) –

+0

Se puede confiar tanto como en cualquier otro comportamiento documentado: si no podemos confiar en que el comportamiento documentado de los métodos no cambiará entre lanzamientos API, estamos bastante condenados. –

1

No. Los algoritmos de Hash no están garantizados, a menos que se especifique lo contrario. Entonces, por ejemplo, la deserialización de las estructuras hash necesita recalcular los códigos hash, y estos valores no deben almacenarse en forma serializada.

2

De acuerdo con la docs: el código hash de un objeto String se calcula como

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 

No estoy seguro de si se trata de una especificación formal o simplemente la aplicación del solar. Como mínimo, debería ser el mismo en todas las máquinas virtuales Sun existentes, independientemente de la plataforma o el sistema operativo.

Cuestiones relacionadas