2009-04-13 21 views
39

Esto es impar. Un compañero de trabajo preguntó sobre la implementación de myArray.hashCode() en java. Pensé que lo sabía, pero luego hice algunas pruebas. Verifica el código a continuación. La extraña idea que noté es que cuando escribí el primer sistema, los resultados fueron diferentes. Tenga en cuenta que es casi como si estuviera informando una dirección de memoria y modificando la clase que movió la dirección o algo así. Solo pensé en compartir.Implementación de Java Array HashCode

int[] foo = new int[100000]; 
java.util.Random rand = new java.util.Random(); 

for(int a = 0; a < foo.length; a++) foo[a] = rand.nextInt(); 

int[] bar = new int[100000]; 
int[] baz = new int[100000]; 
int[] bax = new int[100000]; 
for(int a = 0; a < foo.length; a++) bar[a] = baz[a] = bax[a] = foo[a]; 

System.out.println(foo.hashCode() + " ----- " + bar.hashCode() + " ----- " + baz.hashCode() + " ----- " + bax.hashCode()); 

// returns 4097744 ----- 328041 ----- 2083945 ----- 2438296 
// Consistently unless you modify the class. Very weird 
// Before adding the comments below it returned this: 
// 4177328 ----- 4097744 ----- 328041 ----- 2083945 


System.out.println("Equal ?? " + 
    (java.util.Arrays.equals(foo, bar) && java.util.Arrays.equals(bar, baz) && 
    java.util.Arrays.equals(baz, bax) && java.util.Arrays.equals(foo, bax))); 

Respuesta

77

El método java.lang.ArrayhashCode se hereda de Object, que significa que el código hash depende de la referencia. Para obtener el código hash basado en el contenido de la matriz, use Arrays.hashCode.

Tenga cuidado, aunque es una implementación de código hash superficial. Una implementación profunda también está presente Arrays.deepHashCode.

+1

Gracias por esta respuesta, pero ¿Por qué java.lang.Array no anula los métodos hashCode (y toString) de forma predeterminada? ¿Hay alguna buena razón? –

+4

Porque hashCode necesita ser rápido para ser útil (ya que se usa principalmente para evitar una llamada costosa de .equals), e incluso un valor reducido de hashCode en una matriz podría ser muy lento. Un hashCode que es básicamente aleatorio no duele, simplemente no proporciona ninguna ventaja. Mal menor. – Torque

4

matrices utilizan el código hash por defecto, que se basa en la posición de memoria (pero no es necesariamente la ubicación memoria, ya que es sólo un int y todas las direcciones de memoria no encaja). Puede ver esto también imprimiendo el resultado de System.identityHashCode(foo).

Las matrices son solo equal si son de la misma matriz idéntica. Por lo tanto, los códigos hash de matriz solo serán iguales, generalmente, si son la misma matriz idéntica.

+0

(y los objetos se mueven en la memoria, y si observa los códigos hash, normalmente no se parecen a las direcciones) –

2

La implementación predeterminada para Object.hashCode() es, de hecho, devolver el valor del puntero del objeto, aunque esto depende de la implementación. Por ejemplo, una JVM de 64 bits puede tomar juntos el puntero y el XOR y las palabras de orden alto y bajo. Se recomienda que las subclases anulen este comportamiento si tiene sentido.

Sin embargo, no tiene sentido realizar comparaciones de igualdad en matrices mutables. Si un elemento cambia, entonces los dos ya no son iguales. Para mantener la invariante de que la misma matriz siempre devolverá el mismo código hash sin importar lo que suceda con sus elementos, las matrices no anulan el comportamiento predeterminado de código hash.

Tenga en cuenta que java.util.Arrays proporciona una implementación deepHashCode() para cuando el hash basado en el contenido de la matriz, en lugar de la identidad de la matriz en sí, es importante.

+1

Las máquinas virtuales modernas mueven objetos en la memoria. Se puede usar una dirección actual como semilla, pero el resultado debe almacenarse. –

+1

Moverse en la memoria todavía no hace que se modifique hashCode. –

2

Estoy de acuerdo con el uso de java.util.Arrays.hashCode (o la guayaba Google genérica envoltorio Objects.hashcode) pero ten en cuenta que esto puede causar problemas si está utilizando terracota - ver this link