2010-02-10 12 views

risposta

24

In genere, hashCode() restituisce semplicemente l'indirizzo dell'oggetto in memoria se non lo si sovrascrive.

Da 1:

Per quanto ragionevolmente possibile, il metodo hashCode definito dalla classe Object non ritorno interi distinti per oggetti distinti. (Questo è in genere implementata convertendo l'indirizzo interno dell'oggetto in un intero, ma questa tecnica implementazione non è richiesto dal linguaggio di programmazione Java ™.)

+16

Ho una forte obiezione a "convertire l'indirizzo interno" e mi sono chiesto se Sun/Oracle rimuoverà quella linea dai loro javadoc. Non è possibile garantire che l'indirizzo interno dell'oggetto rimanga invariato nella JVM, il cui garbage collector potrebbe spostarlo durante la compattazione dell'heap. –

+0

Significa che sono sempre unici? – ernesto

+15

L'offerta JavaDoc è corretta, ma la risposta no. L'indirizzo dell'oggetto non viene utilizzato per molti anni. –

0

Si dovrebbe cercare di implementare il codice hash in modo che diversi oggetti saranno dare risultati diversi. Non penso che ci sia un modo standard per farlo.

Leggi questo articolo per alcuni information.

0

Un codice hash è utile per archiviare un oggetto in una raccolta, come un hashset. Consentendo a un oggetto di definire un codice hash come qualcosa di unico, l'algoritmo di HashSet può funzionare in modo efficace.

L'oggetto stesso utilizza l'indirizzo dell'oggetto in memoria, che è molto particolare, ma potrebbe non essere molto utile se due oggetti diversi (ad esempio due stringhe identiche) devono essere considerati uguali, anche se sono duplicati in memoria.

1

l'implementazione di hashcode predefinita fornisce l'indirizzo interno dell'oggetto in jvm, come numero intero a 32 bit. Pertanto, due diversi oggetti (in memoria) avranno hashcode diversi.

Questo è coerente con l'implementazione predefinita di uguale. Se si desidera eseguire l'override degli uguali per i propri oggetti, è necessario adattare hashCode in modo che siano coerenti.

Vedere http://www.ibm.com/developerworks/java/library/j-jtp05273.html per una buona panoramica.

13

L'attuazione di hashCode() può variare da classe a classe, ma il contratto per hashCode() è molto specifica e ha dichiarato in modo chiaro ed esplicito nel Javadocs:

Restituisce un valore codice hash per l'oggetto. Questo metodo è supportato a beneficio di hashtables come quelli forniti da java.util.Hashtable.

Il contratto generale di hashCode è:

  • Ogni volta che viene richiamato sullo stesso oggetto più di una volta nel corso di un'esecuzione di un'applicazione Java, il metodo hashCode deve sempre restituire lo stesso numero intero, fornito alcuna informazioni utilizzate in uguali i confronti sull'oggetto sono modificati. Questo numero intero non deve rimanere coerente da un'esecuzione di un'applicazione a un'altra esecuzione della stessa applicazione.
  • Se due oggetti sono uguali in base al metodo equals (Object), quindi chiamare il metodo hashCode su ciascuno dei due oggetti deve produrre lo stesso risultato intero.
  • Non è necessario che se due oggetti non sono uguali secondo il metodo equals (java.lang.Object), quindi chiamare il metodo hashCode su ciascuno dei due oggetti deve produrre risultati interi distinti.Tuttavia, il programmatore dovrebbe essere consapevole del fatto che la produzione di risultati interi distinti per oggetti non uguali può migliorare le prestazioni degli hashtables.

Per quanto ragionevolmente pratico, il metodo hashCode definito dalla classe Object restituisce interi distinti per oggetti distinti. (Questo è tipicamente implementato convertendo l'indirizzo interno dell'oggetto in numero intero, ma questa tecnica attuazione non è richiesta dal linguaggio di programmazione JavaTM.)

hashCode() è strettamente legata alla equals() e se si ignora equals(), è dovrebbe anche ignorare hashCode().

+1

"hashCode"() è strettamente legato a equals() e se si implementa uno, è necessario implementare l'altro "non è completamente corretto. Hai solo bisogno di sovrascrivere hashCode se uguale è sovrascritto. È tecnicamente valido sovrascrivere hashCode senza sovrascrivere equals. –

+0

@Steve Kuo: abbastanza giusto. Ho riformulato l'ultima frase in base al tuo commento. – Asaph

0

due oggetti con diverso codice hash non devono essere uguali per quanto riguarda equals()

a.hashCode() != b.hashCode() deve implicare !a.equals(b)

Tuttavia, due oggetti che non sono uguali per quanto riguarda equals() può avere lo stesso codice hash. La memorizzazione di questi oggetti in un set o in una mappa diventerà meno efficiente se molti oggetti hanno lo stesso codice hash.

3

Se codice hash non viene sovrascritto si chiamerà codice hash di oggetti, ecco un estratto dalla sua javadoc:

Per quanto è ragionevolmente possibile, il metodo hashCode definito dalla classe Object fa ritorno interi distinti per oggetti distinti . (Questo è in genere implementata convertendo l'indirizzo interno dell'oggetto in un intero, ma questa tecnica implementazione non è richiesto dal linguaggio di programmazione Java ™.)

0

Non proprio una risposta, ma aggiungendo al mio commento precedente

L'indirizzo interno dell'oggetto non può essere garantito per rimanere invariato nella JVM, il cui garbage collector potrebbe spostarlo durante la compattazione dell'heap.

ho cercato di fare qualcosa di simile:

public static void main(String[] args) { 
    final Object object = new Object(); 
    while (true) { 
     int hash = object.hashCode(); 
     int x = 0; 
     Runtime r = Runtime.getRuntime(); 
     List<Object> list = new LinkedList<Object>(); 
     while (r.freeMemory()/(double) r.totalMemory() > 0.3) { 
      Object p = new Object(); 
      list.add(p); 
      x += object.hashCode();//ensure optimizer or JIT won't remove this 
     } 
     System.out.println(x); 
     list.clear(); 
     r.gc(); 
     if (object.hashCode() != hash) { 
      System.out.println("Voila!"); 
      break; 
     } 
    } 
} 

Ma il codice hash infatti non cambia ... qualcuno può dirmi come JDK di Sun implementa in realtà Obect.hashcode?

+0

OpenJDK http://hg.openjdk.java.net/jdk6/jdk6-gate/jdk/file/tip/src/share/classes/java/lang/Object.java ha come funzione nativa. Mi piacerebbe vedere l'implementazione della funzione nativa ... http: //stackoverflow.com/questions/410756/is-it-possible-to-browse-the-source-of-openjdk-online. Chiunque? –

+0

Forse il metodo hashcode predefinito memorizza il primo valore e non lo modifica mai. –

0

restituisce il numero esadecimale di 6 cifre. Di solito è la posizione di memoria dello slot in cui è indirizzato l'oggetto. Da un algoritmo per caso, immagino che JDK faccia doppio hashing (implementazione nativa) che è una delle migliori funzioni di hashing per l'indirizzamento aperto. Questo schema di hashing doppio riduce notevolmente la possibilità di collisioni.

Il seguente post vi darà un appoggio idea -

Java - HashMap confusion about collision handling and the get() method

0

è necessario sovrascrivere hashCode in ogni classe che sostituisce uguale. In caso contrario, si verificherà una violazione del contratto generale per Object.hashCode, che impedirà la classe di funzionare correttamente in conjunction with all hash-based collection s, including HashMap, HashSet, and Hashtable.

43

In JVM HotSpot per impostazione predefinita la prima chiamata di non sovraccarico Object.hashCode o System.identityHashCode un numero casuale viene generata e memorizzata nell'intestazione dell'oggetto. Le chiamate successive a Object.hashCode o System.identityHashCode estraggono questo valore dall'intestazione. Di default non ha nulla in comune con il contenuto dell'oggetto o la posizione dell'oggetto, solo un numero casuale. Questo comportamento è controllato dall'opzione HotSpot JVM -XX:hashCode=n che ha i seguenti valori possibili:

  • 0: utilizzare generatore casuale globale. Questa è l'impostazione predefinita in Java 7. Ha lo svantaggio che le chiamate simultanee da più thread possono causare una condizione di competizione che genererà lo stesso hashCode per oggetti diversi. Anche in ritardi ambientali altamente concomitanti sono possibili a causa della contesa (utilizzando la stessa area di memoria da diversi core della CPU).
  • 5: utilizzare un generatore casuale xor-shift thread-local che è esente dagli svantaggi precedenti. Questa è l'impostazione predefinita in Java 8.
  • 1: usa il puntatore dell'oggetto mescolato con un valore casuale che viene modificato negli eventi "stop-the-world", quindi tra gli eventi stop-the-world (come la garbage collection) ha generato hashCodes sono stabili (per scopi di test/debug)
  • 2: utilizzare sempre 1 (per scopi di test/debug)
  • 3: numeri autoincrementing uso (per scopi di test/debug, anche contatore globale è usato, quindi contesa e race condizioni sono possibili)
  • 4: utilizzare il puntatore dell'oggetto tagliato a 32 bit se necessario (per scopi di test/debug)

Si noti che anche se si imposta -XX:hashCode=4, hashCode non punta sempre sull'indirizzo dell'oggetto. L'oggetto può essere spostato in seguito, ma hashCode rimarrà lo stesso. Anche gli indirizzi degli oggetti sono scarsamente distribuiti (se l'applicazione utilizza non tanta memoria, la maggior parte degli oggetti si troverà l'uno vicino all'altro), quindi si potrebbe finire con tabelle hash sbilanciate se si utilizza questa opzione.

Problemi correlati