Heim >Java >javaLernprogramm >Beispielcode-Freigabe für die Implementierung der hashCode-Methode in Java

Beispielcode-Freigabe für die Implementierung der hashCode-Methode in Java

黄舟
黄舟Original
2017-03-28 10:47:521888Durchsuche

Sie wissen, dass die eindeutige Identität eines Objekts nicht einfach durch das Schreiben eines netten Gleichwerts erreicht werden kann Die Implementierung der

ist großartig, aber jetzt müssen Sie auch die HashCode-Methode implementieren. Mal sehen, warum und wie man es richtig macht 🎜>

Equality and Hash Code

Gleichheit ist aus allgemeiner Sicht, Hash-Codes sind eher technischer Natur, und wenn wir Schwierigkeiten haben, sie zu verstehen, können wir sagen, dass sie nur ein Implementierungsdetail sind, um die Leistung zu verbessern Strukturen verwenden die Methode „equals“, um zu bestimmen, ob sie ein Element enthalten. Zum Beispiel:

Diese

Variable

enthält true , da „b“ nicht dieselbe Instanz ist (Darüber hinaus ist es verschwenderischer, wenn man den String-Resident ignoriert), indem man jedes Element von

List<String> list = Arrays.asList("a", "b", "c");
boolean contains = list.contains("b");
vergleicht und dann das Vergleichsergebnis

zuweist, obwohl die Datenstruktur der gesamten Klasse optimiert wurde, um sie zu verbessern Leistung. Sie führen Vergleiche durch, indem sie die potenzielle Instanzgleichheit verringern, anstatt jedes enthaltene Element zu vergleichen:

Verknüpfung Beim Vergleich wird eine Instanz durch einen ganzzahligen Wert durch Vergleich des Hash-Codes ersetzt. Nicht unbedingt gleich, aber gleiche Instanzen müssen den gleichen Hash-Wert haben (oder sollten, wir werden dies gleich besprechen). und kann durch contains identifiziert werden. Unter ihnen ist

Sie funktionieren normalerweise so:

HashHashMap Wenn ein Element Wird hinzugefügt, wird sein Hash-Code hinzugefügt, um den

Index

des inneren

Arrays
    (des sogenannten Buckets)
  • zu berechnen Wenn ja, haben ungleiche Elemente die gleichen Hash-Codes, sie landen im selben Bucket und werden gebündelt, z. B. durch Hinzufügen zur Liste

  • Wenn eine Instanz für das
  • kommt Bei der Operation wird der Hash-Code verwendet, um den Bucket-Wert (Indexwert) zu berechnen. Die Instanzen werden nur dann verglichen, wenn ein Element mit dem entsprechenden Indexwert vorhanden ist > sind in der Klasse <. code>Object

    definiert Hash-Methode. Gedanke

  • Wenn
  • als Abkürzung zur Bestimmung der Gleichheit verwendet wird, sollten wir uns nur um eines kümmern: Gleiche Objekte sollten den gleichen Hash-Code haben, deshalb überschreiben wir den

    -Methode Schließlich müssen wir eine passende contains-Implementierung erstellen! Andernfalls haben gleiche Objekte möglicherweise nicht den gleichen Hash-Code, da sie den Standardwert von

    erreichen.

RichtlinienequalshashCode<a href="http://www.php.cn/wiki/60.html" target="_blank">Object</a>Zitat

aus der offiziellen Dokumentation

HashCode-Allgemeinkonvention:hashCode* Rufen Sie die laufende Java-Anwendung auf. Für dasselbe Objekt muss die Methode hashCode immer die gleiche Ganzzahl zurückgeben. Diese Ganzzahl muss nicht über verschiedene Java-Anwendungen hinweg konsistent sein. equals* Vergleichen Sie gemäß der Methode equal(Object) Wenn zwei Objekte gleich sind, muss der Aufruf der Methode hashCode für die beiden Objekte zum gleichen Ergebnis führen. hashCode* Laut der Methode equal(Object) führt der Aufruf der Methode hashCode für die beiden Objekte nicht unbedingt zu unterschiedlichen ganzzahligen Ergebnissen, wenn die beiden Objekte nicht gleich sind.

Programmierer

sollten sich jedoch darüber im Klaren sein, dass die Erzeugung unterschiedlicher ganzzahliger Ergebnisse für ungleiche Objekte möglicherweise die Leistung der Hash-Tabelle verbessert. Object's

Der erste Punkt spiegelt das Attribut „gleiche Konsistenz“ HashCode wider und der zweite Punkt ist die Anforderung, die wir oben gestellt haben. Das dritte veranschaulicht ein wichtiges Detail, das wir später besprechen werden.

HashCode-ImplementierungDas Folgende ist eine sehr einfache Implementierung von


Person, die den Hash-Code durch Kombination mehrerer Felder berechnet. Sie werden alle durch die

-Funktion von berechnet.

Felder auswählen

Aber welche Felder hängen zusammen? Die Anforderung hilft uns bei der Beantwortung dieser Frage: Wenn gleiche Objekte den gleichen Hash-Code haben müssen, ist die Berechnung des Hash-Codes nicht möglich. Alle Felder werden nicht verwendet zur Gleichstellungsprüfung sollten enthalten sein. (Ansonsten unterscheiden sich die beiden Objekte nur in diesen Feldern, können aber dennoch gleich sein. In diesem Fall sind die Hash-Codes der beiden Objekte unterschiedlich.)

Es wird also verwendet, wenn die Hash-Gruppenfelder es sollten gleich sein. Eine Teilmenge von Feldern. Standardmäßig verwenden beide dieselben Felder, es sind jedoch einige Details zu beachten.

一致性

首先,有一致性的要求。它应该相当严格。虽然它允许如果一些字段改变对应的哈希码发生变化(对于可变的类是不可避免的),但是哈希数据结构并不是为这种场景准备的。

正如我们以上所见的哈希码用于确定元素的桶。但如果hash-relevant字段发生了改变,并不会重新计算哈希码、也不会更新内部数组。

这意味着以后通过相等的对象,甚至同一实例进行查询也会失败,数据结构计算当前的哈希码与之前存储实例计算的哈希码并不一致,并是错误的桶。

结论:最好不要使用可变字段计算哈希码!

性能

哈希码最终计算的频率与可能调用equals差不多,那么这里将是影响性能的关键部分,因此考虑此部分性能也是非常有意义的。并且与equals相比,优化之后又更大的上升空间。

除非使用非常复杂的算法或者涉及非常多的字段,那么计算哈希码的运算成本是微不足道的、同样也是不可避免的。但是也应该考虑是否需要包含所有的字段来进行运算。集合需要特别警惕的对待。以Listssets为例,将会包含集合里面的每一个元素来计算哈希码。是否需要调用它们需要具体情况具体分析。

如果性能是至关重要的,使用Objects.hash因为需要为varargs创建一个数组也许并不是最好的选择。但一般规则优化是适用的:不要过早地使用一个通用的散列码算法,也许需要放弃集合,只有优化分析显示潜在的改进。

碰撞

总是关注性能,这个实现怎么呢?

@Override
public int hashCode() {
    return 0;
}

快是肯定的。相等的对象将具有相同的哈希码。并且,没有可变的字段!

但是,我们之前说过的桶呢?!这种方式下所有的实例将会有相同的桶!这将会导致一个链表来包含所有的元素,这样一来将会有非常差的性能。每次调用contains将会触发对整个list线性扫描。

我们希望尽可能少的元素在同一个桶!一个算法返回变化多端的哈希码,即使对于非常相似的对象,是一个好的开始。

怎样才能达到上面的效果部分取决于选取的字段,我们在计算中包含更多的细节,越有可能获取到不同的哈希码。注意:这个与我们所说的性能是完全相反的。因此,有趣的是,使用过多或者过少的字段都会导致糟糕的性能。

防止碰撞的另一部分是使用实际计算散列的算法。

计算Hsah

最简单的方法来计算一个字段的哈希码是通过直接调用hashCode,结合的话会自动完成。常见的算法是首先在以任意数量的数值(通常是基本数据类型)反复进行相乘操作再与字段哈希码相加

int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
return result;

这可能导致溢出,但是不是特别有问题的,因为他们并没有产生Java异常。

注意,即使是非常良好的的哈希算法也可能因为输入特定的模式的数据有导致频繁碰撞。作为一个简单的例子假设我们会计算点的散列通过增加他们的x和y坐标。当我们处理f(x) = -x线上的点时,线上的点都满足:x + y == 0,将会有大量的碰撞。

但是:我们可以使用一个通用的算法,只到分析表明并不正确,才需要对哈希算法进行修改。

总结

我们了解到计算哈希码就是压缩相等的一个整数值:相等的对象必须有相同的哈希码,而出于对性能的考虑:最好是尽可能少的不相等的对象共享相同的哈希码。

这就意味着如果重写了equals方法,那么就必须重写hashCode方法

当实现hashCode

  • 使用与equals中使用的相同的字段(或者equals中使用字段的子集)

  • 最好不要包含可变的字段。

  • 对集合不要考虑调用hashCode

  • 如果没有特殊的输入特定的模式,尽量采用通用的哈希算法

记住hashCode性能,所以除非分析表明必要性,否则不要浪费太多的精力。


Das obige ist der detaillierte Inhalt vonBeispielcode-Freigabe für die Implementierung der hashCode-Methode in Java. 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