Heim  >  Artikel  >  Java  >  equal()-Methode und hashCode()-Methode (ausführliche Einführung)

equal()-Methode und hashCode()-Methode (ausführliche Einführung)

青灯夜游
青灯夜游Original
2019-11-23 15:18:372613Durchsuche

Die Basisklasse Object von Java bietet einige Methoden, darunter die Methode equal(), mit der ermittelt wird, ob zwei Objekte gleich sind, und die Methode hashCode(), mit der der Hash-Code des Objekts berechnet wird. Weder equal() noch hashCode() sind endgültige Methoden und können überschrieben werden.

equal()-Methode und hashCode()-Methode (ausführliche Einführung)

In diesem Artikel werden einige Probleme vorgestellt, die bei der Verwendung und Umschreibung der beiden Methoden beachtet werden müssen.

1. equal()-Methode

Die equal()-Methode in der Object-Klasse ist wie folgt implementiert:

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

Aus dieser Implementierung ist ersichtlich, dass die Implementierung der Object-Klasse den Algorithmus mit dem höchsten Differenzierungsgrad übernimmt. Das heißt, solange die beiden Objekte nicht dasselbe Objekt sind, muss equal() false zurückgeben .

Obwohl wir die Methode equal() beim Definieren einer Klasse überschreiben können, gibt es einige Vorsichtsmaßnahmen, die beim Implementieren der Methode equal() beachtet werden sollten:

(1) Reflexivität: x.equals(x) muss true zurückgeben.

(2) Symmetrie: Die Rückgabewerte von x.equals(y) und y.equals(x) müssen gleich sein.

(3) Transitivität: x.equals(y) ist wahr und y.equals(z) ist auch wahr, dann muss x.equals(z) wahr sein.

(4) Konsistenz: Wenn sich die von den Objekten x und y in equal() verwendeten Informationen nicht ändern, bleibt der Wert von x.equals(y) immer unverändert.

(5) Nicht null: x ist nicht null und y ist null, dann muss x.equals(y) falsch sein.

2. hashCode()-Methode

1. Objekt-hashCode()

Die hashCode()-Methode in der Object-Klasse wird wie folgt deklariert:

public native int hashCode();

Es ist ersichtlich, dass hashCode() eine native Methode ist und der Rückgabewerttyp tatsächlich eine Ganzzahl ist. Diese native Methode konvertiert das Objekt. Die Adresse im Speicher wird als Hash-Code zurückgegeben, wodurch sichergestellt wird, dass der Rückgabewert für verschiedene Objekte unterschiedlich ist.

Ähnlich wie die Methode equal() kann die Methode hashCode() überschrieben werden. Das JDK erklärt die Funktion der Methode hashCode() und die Vorsichtsmaßnahmen bei der Implementierung:

(1) hashCode() funktioniert in einer Hash-Tabelle, wie z. B. java.util.HashMap.

(2) Wenn sich die vom Objekt in equal() verwendeten Informationen nicht geändert haben, bleibt der Wert hashCode() immer unverändert.

(3) Wenn zwei Objekte mithilfe der Methode equal() als gleich beurteilt werden, sollte auch die Methode hashCode() gleich sein.

(4) Wenn zwei Objekte mit der Methode equal() als ungleich beurteilt werden, ist hashCode() nicht erforderlich und muss ungleich sein. Entwickler sollten sich jedoch darüber im Klaren sein, dass ungleiche Objekte unterschiedliche hashCode erzeugen können von Hash-Tabellen.

2. Die Rolle von hashCode()

Im Allgemeinen funktioniert hashCode() in Hash-Tabellen wie HashSet, HashMap usw.

Wenn wir ein Objekt zu einer Hash-Tabelle hinzufügen (z. B. HashSet, HashMap usw.), rufen wir zuerst die Methode hashCode() auf, um den Hash-Code des Objekts zu berechnen Lokalisieren Sie das Objekt direkt in der Hash-Tabelle (im Allgemeinen der Modulus des Hash-Codes zur Größe der Hash-Tabelle). Wenn sich an dieser Position kein Objekt befindet, können Sie das Objekt direkt an dieser Position einfügen. Wenn sich an dieser Position Objekte befinden (es können mehrere vorhanden sein, die über eine verknüpfte Liste implementiert werden), rufen Sie die Methode equal() auf, um zu vergleichen, ob Diese Objekte sind gleich dem Objekt. Wenn sie gleich sind, müssen Sie das Objekt nicht speichern. Wenn sie nicht gleich sind, fügen Sie das Objekt der verknüpften Liste hinzu.

Dies erklärt auch, warum equals() gleich ist, dann muss hashCode() gleich sein. Wenn zwei Objekte equal() gleich sind, sollten sie nur einmal in der Hash-Tabelle erscheinen (z. B. HashSet, HashMap usw.); wenn hashCode() nicht gleich ist, werden sie an verschiedenen Stellen in gehasht Hash-Tabelle Position, kommt mehr als einmal in der Hash-Tabelle vor.

Tatsächlich enthält das geladene Objekt in der JVM drei Teile im Speicher: Objektheader, Instanzdaten und Füllung. Darunter enthält der Objektheader einen Zeiger auf den Objekttyp und MarkWord, und MarkWord enthält nicht nur die GC-Generierungsaltersinformationen und Sperrstatusinformationen des Objekts, sondern auch den Hashcode des Objekts ; Die Objektinstanzdaten sind die tatsächlich vom Objekt gespeicherten Informationen. Der Auffüllteil dient nur als Platzhalter, da HotSpot erfordert, dass die Startadresse des Objekts ein ganzzahliges Vielfaches von 8 Bytes sein muss.

3. Implementierung von equal() und hashCode() in String

Der relevante Implementierungscode in der String-Klasse lautet wie folgt:

    private final char value[];
    private int hash; // Default to 0
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

Die folgenden Punkte sind aus dem Code ersichtlich:

1. String-Daten sind endgültig, das heißt, sobald ein String-Objekt erstellt wurde, können sie nicht in der Form von String s geändert werden = "hello"; s = "world"; Anweisung: Wenn s = "world" ausgeführt wird, ändert sich der Wert des String-Objekts nicht in "world", sondern es wird ein neues String-Objekt erstellt und die s-Referenz zeigt auf das neue Objekt.

2. Die String-Klasse speichert das Ergebnis von hashCode() als Hash-Wert zwischen, um die Leistung zu verbessern.

3. Die Bedingung dafür, dass das String-Objekt equal() gleich ist, ist, dass beide String-Objekte die gleiche Länge haben und nicht unbedingt dasselbe Objekt sein müssen.

4. Die HashCode()-Berechnungsformel von String lautet: s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[ n -1]

Die Hauptgründe für die Verwendung der Zahl 31 im Berechnungsprozess von hashCode() sind folgende:

1、使用质数计算哈希码,由于质数的特性,它与其他数字相乘之后,计算结果唯一的概率更大,哈希冲突的概率更小。

2、使用的质数越大,哈希冲突的概率越小,但是计算的速度也越慢;31是哈希冲突和性能的折中,实际上是实验观测的结果。

3、JVM会自动对31进行优化:31 * i == (i 77c98ee81678acf12c851e5747f5e864>> 32))

 (4) 如果是float值,则计算Float.floatToIntBits(f)

 (5) 如果是double值,则计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)去处理long,得到int

 (6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。否则需要为这个域计算一个范式,比如当这个域的值为null的时候,那么hashCode 值为0

 (7) 如果是数组,那么需要为每个元素当做单独的域来处理。java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。 

C、最后,把每个域的散列码合并到对象的哈希码中。

下面通过一个例子进行说明。在该例中,Person类重写了equals()方法和hashCode()方法。因为equals()方法中只使用了name域和age域,所以hashCode()方法中,也只计算name域和age域。

对于String类型的name域,直接使用了String的hashCode()方法;对于int类型的age域,直接用其值作为该域的hash。

public class Person {
	private String name;
	private int age;
	private boolean gender;

	public Person() {
		super();
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public boolean isGender() {
		return gender;
	}
	public void setGender(boolean gender) {
		this.gender = gender;
	}

	@Override
	public boolean equals(Object another) {
		if (this == another) {
			return true;
		}
		if (another instanceof Person) {
			Person anotherPerson = (Person) another;
			if (this.getName().equals(anotherPerson.getName()) && this.getAge() == anotherPerson.getAge()) {
				return true;
			} else {
				return false;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		int hash = 17;
		hash = hash * 31 + getName().hashCode();
		hash = hash * 31 + getAge();
		return hash;
	}
}

推荐教程:java教程

Das obige ist der detaillierte Inhalt vonequal()-Methode und hashCode()-Methode (ausführliche Einführung). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn