2009-04-13 6 views
39

Questo è dispari. Un collega ha chiesto informazioni sull'implementazione di myArray.hashCode() in java. Pensavo di saperlo, ma poi ho fatto alcuni test. Controlla il codice qui sotto. La cosa strana che ho notato è che quando ho scritto il primo sys i risultati erano diversi. Nota che è quasi come se stesse riportando un indirizzo di memoria e modificando la classe spostato l'indirizzo o qualcosa del genere. Ho pensato di condividerlo.Implementazione HashCode dell'array Java

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))); 

risposta

77

Procedimento java.lang.ArrayhashCode viene ereditato da Object, che significa che il codice hash dipende dal riferimento. Per ottenere l'hashcode in base al contenuto dell'array, utilizzare Arrays.hashCode.

Attenzione però è un'implementazione di hashcode poco profonda. È anche presente un'implementazione profonda Arrays.deepHashCode.

+1

Grazie per questa risposta, ma perché java.lang.Array non sovrascrive i metodi hashCode (e toString) per impostazione predefinita? C'è qualche buona ragione? –

+4

Perché hashCode deve essere veloce per essere utile (dato che è usato principalmente per prevenire una costosa chiamata di .equals), e persino un valore minimo hashCode su un array potrebbe potenzialmente essere molto lento. Un hashCode che è fondamentalmente casuale non fa male, non fornisce alcun vantaggio. Minore di due mali. – Torque

4

Array utilizzano il codice predefinito di hash, che si basa sulla posizione di memoria (ma non è necessariamente la posizione di memoria, dal momento che è solo un int e tutti gli indirizzi di memoria non si adatta). Puoi vedere questo anche stampando il risultato di System.identityHashCode(foo).

Gli array sono solo equal se sono la stessa matrice identica. Quindi, i codici di hash dell'array saranno uguali, generalmente, se sono la stessa matrice identica.

+0

(e gli oggetti vengono spostati in memoria e se si guardano i codici hash in genere non sembrano indirizzi) –

2

L'implementazione predefinita per Object.hashCode() restituisce effettivamente il valore del puntatore dell'oggetto, sebbene questo dipenda dall'implementazione. Ad esempio, una JVM a 64 bit può prendere insieme il puntatore e XOR e le parole di ordine alto e basso. Le sottoclassi sono incoraggiate a ignorare questo comportamento se ha senso.

Tuttavia, non ha senso eseguire confronti di uguaglianza su matrici mutevoli. Se un elemento cambia, allora i due non sono più uguali. Per mantenere invariato il fatto che lo stesso array restituirà sempre lo stesso hashCode indipendentemente da cosa succede ai suoi elementi, gli array non sovrascrivono il comportamento predefinito di hashcode.

Si noti che java.util.Arrays fornisce un'implementazione deepHashCode() per quando l'hashing basato sul contenuto dell'array, piuttosto che sull'identità dell'array stesso, è importante.

+1

Le moderne macchine virtuali spostano gli oggetti in memoria. Un indirizzo corrente può essere utilizzato come seme, ma il risultato deve essere memorizzato. –

+1

Spostarsi in memoria ancora non causa la modifica dell'hashCode. –

2

Sono d'accordo con l'utilizzo di java.util.Arrays.hashCode (oppure Google guava wrapper generico Objects.hashcode), ma essere consapevoli che questo può causare problemi se si utilizza Terracotta - vedere this link