Wenn wir die Methode hashcode() lernen wollen, müssen wir die folgenden Aspekte Schritt für Schritt herausfinden:
1. Der Ursprung von hashcode()
Hashcode basiert auf JDK für das Objekt Ein int-Wert, der aus einer Adresse, einer Zeichenfolge oder einer Zahl berechnet wird. Wie wird er berechnet? Die Antwort ist Hashtabelle. Eine Hashtabelle ist eine Datenstruktur, auf die basierend auf dem Schlüsselwert direkt zugegriffen wird. Das ist vielleicht zu offiziell. Ich verstehe, dass Hashcode ein Wert ist, der durch eine Funktion abgebildet wird Der durch die Hash-Funktion erhaltene Hash-Wert ist Wert = f (Schlüssel). Nachdem wir den Hashcode verstanden haben, wissen wir, wofür die Methode hashcode () verwendet wird, um die Methode hashcode () zu berechnen und zurückzugeben.
2. Die Rolle von hashcode()
Der Hauptvorteil einer Hash-Tabelle besteht darin, dass sie die Sucheffizienz verbessern kann. Wenn wir uns die API ansehen, können wir feststellen, dass hashcode() eine Methode von Object ist. Man kann auch sagen, dass Objekte aller Klassen in Java entsprechend ihrer Verbesserungseigenschaften aufgerufen werden können Sucheffizienz, wir wenden es hauptsächlich in an. Um ordnungsgemäß mit Hash-basierten Sammlungen zu arbeiten, umfassen solche Hash-Sammlungen HashSet, HashMap und HashTable. Doppelte Elemente dürfen in der Menge nicht vorhanden sein. Wenn wir also ein neues Element hinzufügen müssen, wie können wir dann beurteilen, ob das Element bereits vorhanden ist? Vielleicht denken die meisten Leute darüber nach, die Methode „equals“ aufzurufen, um einen nach dem anderen zu vergleichen. Diese Methode ist tatsächlich machbar. Wenn die Sammlung jedoch bereits 10.000 oder mehr Daten enthält und Sie die Methode „equals“ verwenden, um sie einzeln zu vergleichen, muss die Effizienz ein Problem sein. Zu diesem Zeitpunkt spiegelt sich die Rolle der HashCode-Methode wider. Wenn der Sammlung ein neues Objekt hinzugefügt wird, wird zunächst die HashCode-Methode dieses Objekts aufgerufen, um den entsprechenden Hashcode-Wert abzurufen Die Tabelle wird zum Speichern des Hashcode-Werts des Objekts verwendet. Wenn der Hashcode-Wert nicht in der Tabelle vorhanden ist, kann er direkt ohne Vergleich gespeichert werden Wenn es dasselbe ist, wird es nicht verglichen. Wenn es nicht gleich ist, werden andere Adressen gehasht, sodass ein Problem bei der Konfliktlösung besteht, also die Anzahl der tatsächlichen Aufrufe Methode ist stark reduziert. Der folgende Code ist die spezifische Implementierung der Put-Methode in java.util.HashMap:
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
Die Put-Methode wird verwendet, um neue Elemente zu HashMap hinzuzufügen. Aus der spezifischen Implementierung der Put-Methode ist dies möglich Das ist zu sehen. Rufen Sie die HashCode-Methode auf, um den HashCode-Wert des Elements abzurufen, und prüfen Sie dann, ob der HashCode-Wert in der Tabelle vorhanden ist. Rufen Sie die Methode equal auf, um erneut zu bestimmen, ob das Element vorhanden ist den Wert value, andernfalls fügen Sie das neue Element zur HashMap hinzu. Daraus ist ersichtlich, dass die Methode hashCode dazu dient, die Anzahl der Aufrufe der Methode equal zu reduzieren und dadurch die Programmeffizienz zu verbessern.
3.hashcode()-Methode und equal()-Methode
Hier müssen mehrere Probleme beachtet werden. Um festzustellen, ob Objekte gleich sind, können Sie die Methode hashcode() verwenden. Die Antwort lautet: Nein, Sie müssen die Methode equal() verwenden. Zwei verschiedene Objekte können denselben Hashcode haben, aber zwei Objekte mit unterschiedlichen Hashcodes müssen unterschiedlich sein.
Ein weiteres zu beachtendes Problem: Beim Entwerfen einer Klasse ist es notwendig, die Methode „equals“, z. B. die String-Klasse, zu überschreiben. Beachten Sie jedoch, dass Sie beim Umschreiben der Methode „equals“ auch die Methode „hashCode“ überschreiben müssen . Schauen wir uns ein Beispiel an, das nur die Methode „equals“ überschreibt:
import java.util.HashMap; import java.util.HashSet; import java.util.Set; class People{ private String name; private int age; public People(String name,int age) { this.name = name; this.age = age; } public void setAge(int age){ this.age = age; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return this.name.equals(((People)obj).name) && this.age== ((People)obj).age; } } public class Main { public static void main(String[] args) { People p1 = new People("Jack", 12); System.out.println(p1.hashCode()); HashMap<People, Integer> hashMap = new HashMap<People, Integer>(); hashMap.put(p1, 1); System.out.println(hashMap.get(new People("Jack", 12))); } }
Wenn zwei Personenobjekte denselben Namen und dasselbe Alter haben, werden sie als dieselbe Person betrachtet. Die ursprüngliche Absicht dieses Codes besteht darin, dass das Ausgabeergebnis dieses Codes „1“ ist, aber tatsächlich wird „null“ ausgegeben.
Obwohl durch das Überschreiben der Methode „equals“ zwei Objekte mit demselben Namen und Alter logisch als gleiche Objekte beurteilt werden (ähnlich der String-Klasse), müssen Sie wissen, dass die Methode hashCode standardmäßig die Objektadresse speichert Abbildung. Es ist nicht überraschend, dass die Ausgabe des obigen Codes „null“ ist. Der Grund ist sehr einfach. Das Objekt, auf das p1 und System.out.println(hashMap.get(new People("Jack", 12))) zeigen, erzeugt zwei Objekte . , ihre Speicheradressen müssen unterschiedlich sein. Wenn die Hashmap eine Get-Operation ausführt, wird daher direkt Null zurückgegeben, da die erhaltenen Hashcdoe-Werte unterschiedlich sind. Wenn das Ausgabeergebnis des obigen Codes „1“ sein soll, ist dies sehr einfach. Sie müssen nur die Methode hashCode neu schreiben, damit die Methode equal und die Methode hashCode immer logisch konsistent sind.
import java.util.HashMap; import java.util.HashSet; import java.util.Set; class People{ private String name; private int age; public People(String name,int age) { this.name = name; this.age = age; } public void setAge(int age){ this.age = age; } @Override public int hashCode() { // TODO Auto-generated method stub return name.hashCode()*37+age; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return this.name.equals(((People)obj).name) && this.age== ((People)obj).age; } } public class Main { public static void main(String[] args) { People p1 = new People("Jack", 12); System.out.println(p1.hashCode()); HashMap<People, Integer> hashMap = new HashMap<People, Integer>(); hashMap.put(p1, 1); System.out.println(hashMap.get(new People("Jack", 12))); } }
Das Folgende ist ein Zitat aus dem Buch Effective Java:
Während der Ausführung des Programms werden die in der Vergleichsoperation der Methode equal verwendeten Informationen nicht geändert Bei mehreren Aufrufen desselben Objekts muss die Methode hashCode stets dieselbe Ganzzahl zurückgeben.
Wenn zwei Objekte gemäß dem Methodenvergleich gleich sind, muss der Aufruf der hashCode-Methode der beiden Objekte dasselbe ganzzahlige Ergebnis zurückgeben.
Wenn zwei Objekte gemäß der Methode equal nicht gleich sind, muss die Methode hashCode nicht unbedingt unterschiedliche Ganzzahlen zurückgeben.
Der zweite und dritte Punkt sind leicht zu verstehen, aber der erste wird oft ignoriert. Es gibt auch einen Absatz ähnlich dem ersten auf Seite P495 des Buches „Java Programming Thoughts“:
„Der wichtigste Faktor beim Entwerfen von hashCode() ist: Immer wenn hashCode() für dasselbe Objekt aufgerufen wird, sollte es denselben Wert erzeugen. Wenn ein Objekt mit put() zu einer HashMap hinzugefügt wird, wird ein hashCdoe erstellt Wenn bei Verwendung von get() ein anderer HashCode-Wert generiert wird, kann das Objekt nicht abgerufen werden. Wenn Ihre HashCode-Methode daher auf flüchtigen Daten im Objekt basiert, sollten Benutzer vorsichtig sein, da diese Daten auftreten , generiert die Methode hashCode() einen anderen Hash-Code.“