In che modo .equals e .hashCode predefiniti funzioneranno per le mie classi?


106

Dì che ho la mia classe

public class MyObj { /* ... */ }

Ha alcuni attributi e metodi. NON implementa uguale, NON implementa hashCode.

Una volta che chiamiamo uguale e hashCode, quali sono le implementazioni predefinite? Dalla classe Object? E cosa sono? Come funzionerà il valore predefinito uguale? Come funzionerà l'hashCode predefinito e cosa restituirà? == controllerà solo se fanno riferimento allo stesso oggetto, quindi è facile, ma per quanto riguarda i metodi equals () e hashCode ()?

Risposte:


94

Sì, l'implementazione predefinita è Object (in generale; se erediti da una classe che ha ridefinito uguale e / o hashCode, utilizzerai invece quell'implementazione).

Dalla documentazione:

equals

Il metodo equals per la classe Object implementa la relazione di equivalenza più discriminante possibile sugli oggetti; ovvero, per qualsiasi valore di riferimento non nullo x e y, questo metodo restituisce vero se e solo se x e y si riferiscono allo stesso oggetto (x == y ha il valore vero).

hashCode

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


50

Da Objectuna delle implementazioni JVM:

public boolean equals(Object object) {
    return this == object;
}

public int hashCode() {
    return VMMemoryManager.getIdentityHashCode(this);
}

In entrambi i casi si tratta solo di confrontare gli indirizzi di memoria degli oggetti in questione.


7
Da quale versione di JDK proviene? A v6u23 ea:public native int hashCode();
khachik

@kha - Hai ragione, penso di aver rintracciato una delle implementazioni native per vedere cosa ha effettivamente fatto
Brad Mace

10

Esistono implementazioni predefinite di equals()e hashCode()in Object. Se non fornisci la tua implementazione, verranno utilizzate quelle. Per equals(), questo significa un ==confronto: gli oggetti solo sarà uguale se sono esattamente lo stesso oggetto. Perché hashCode()il Javadoc ha una buona spiegazione.

Per ulteriori informazioni, vedere Effective Java, Capitolo 3 (pdf), elemento 8.


1

Sì, dalla Objectclasse poiché la tua classe estende Object in modo implicito. equalssemplicemente ritorna this == obj. hashCodel'implementazione è nativa. Solo una supposizione: restituisce il puntatore all'oggetto.


2
È un puntatore all'oggetto che si trova in memoria, ma non è un indirizzo di memoria dell'oggetto. Il GC può spostare l'oggetto in memoria e il codice hash rimarrà lo stesso.
Jeremy

@ Jeremy Grazie. stackoverflow.com/questions/2427631/… potrebbe essere interessante.
khachik

1

Se non si fornisce la propria implementazione, verrà utilizzata una derivata da Object. Va bene, a meno che non si preveda di inserire le istanze della propria classe in, ad esempio, HashSet (qualsiasi raccolta che effettivamente utilizza hashCode ()), o qualcosa che deve controllare l'uguaglianza dell'oggetto (ovvero il metodo contains () di HashSet). Altrimenti funzionerà in modo errato, se è quello che stai chiedendo.

È abbastanza facile fornire la propria implementazione di questi metodi grazie a HashCodeBuilder ed EqualsBuilder di Apache Commons Lang .


(a) Perché dici che l'implementazione predefinita di "uguale" della classe Object non funzionerà correttamente con HashSet? Ciò contraddice le altre risposte in questa pagina. (b) Grazie per i collegamenti a Commons Lang.
Basil Bourque

1
@Basil: non credo che sia in contraddizione. Ovviamente l'implementazione predefinita funzionerebbe ... in qualche modo, ma non nel modo previsto. Cioè, poiché equals () utilizza l'uguaglianza dei riferimenti, due oggetti altrimenti identici sarebbero "diversi" agli occhi dell'implementazione predefinita. Di conseguenza, potresti finire per avere due istanze diverse della stessa identica cosa nel tuo set. E l'uso piuttosto tipico dei set è quando si desidera eliminare i duplicati ...
Paweł Dyda

@ PawełDyda: il comportamento predefinito è generalmente corretto per i tipi modificabili. Se Fooe Barsono riferimenti a due differenti istanze di un tipo mutabile, ed esiste un metodo (ad esempio SomeMutatingMethod) tale che Foo.SomeMutatingMethod()non influisce Barallo stesso modo Foo, quella differenza dovrebbe essere sufficiente per considerare gli oggetti come disuguali.
supercat

0

Il developerworks di IBM dice:

In questa implementazione predefinita, due riferimenti sono uguali solo se si riferiscono allo stesso identico oggetto. Allo stesso modo, l'implementazione predefinita di hashCode () fornita da Object viene derivata mappando l'indirizzo di memoria dell'oggetto su un valore intero.

Tuttavia, per essere sicuri dei dettagli esatti di implementazione per la versione Java di un particolare fornitore è probabilmente meglio guardare come fonte (se disponibile)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.