目錄
是比較浪費的,雖然整個類別的資料結構進行了最佳化,能夠提升效能。實例所包含的每個元素。的實例不一定相等,但相等的實例一定具有有相同的哈希值。 Hash
HashCode實作
選擇欄位但哪些欄位是相關的嗎?需求將會幫助我們回答這個問題:如果相等的物件必須具有相同的雜湊碼,那麼計算雜湊碼就不應包括任何不用於相等檢查的欄位。 (否則兩個物件只是這些字段不同但是仍然有可能會相等,此時他們這兩個物件哈希碼卻會不相同。)
一致性
性能
碰撞
计算Hsah
总结
首頁 Java java教程 Java實作hashCode方法的範例程式碼分享

Java實作hashCode方法的範例程式碼分享

Mar 28, 2017 am 10:47 AM

你知道一個物件的唯一標誌不能只寫一個漂亮的equals來實作

太棒了,不過現在你也必須實作hashCode方法。

##相等和哈希碼

相等是從一般的方面來講,哈希碼更加具有技術性。來提高了效能。 ,雖然”b」是不相同的實例(此外,忽略字串駐留),但是他們是相等的。

是比較浪費的,雖然整個類別的資料結構進行了最佳化,能夠提升效能。實例所包含的每個元素。的實例不一定相等,但相等的實例一定具有有相同的哈希值。 Hash

來識別他們的,其中,

HashMap

是其中最著名的代表。當增加一個元素,它的雜湊碼是用來計算內部

陣列

索引(即所謂的桶)

如果是,不相等的元素有相同的哈希碼,他們最終在同一個桶上並且捆綁在一起,例如通過添加到列表。 contains操作時,它的雜湊碼將用來計算桶值(索引值),只有當對應索引值上存在元素時,才會對實例進行比較。 ##因此

equals

hashCode

是定義在Object類別中。

#如果

hashCode

作為快捷方式來確定相等,那麼只有一件事我們應該關心:相等的物件應該具有相同的雜湊碼,這也是為什麼如果我們重寫了* 呼叫執行Java應用程式中的相同物件,hashCode方法必須始終傳回相同的整數。這個整數不需要在不同的Java應用程式中保持一致。

* 根據equals(Object)的方法來比較,如果兩個物件是相等的,兩個物件呼叫hashCode方法必須產生相同的結果。 * 根據equals(Object)的方法是比較,如果兩個物件是不相等的,那麼兩個物件呼叫hashCode方法並不一定會產生不同的整數的結果。但是,程式設計師應該意識到給不相等的物件產生不同的整數結果將有可能提高雜湊表的效能。 <a href="http://www.php.cn/wiki/60.html" target="_blank">第一點反映出了相等的一致性</a>屬性,第二個就是我們上面提出的要求。第三個闡述了一個重要的細節,我們稍後再討論。

HashCode實作

下面是非常簡單的Person.hashCode的實作<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>List&lt;String&gt; list = Arrays.asList(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;); boolean contains = list.contains(&quot;b&quot;);</pre><div class="contentsignin">登入後複製</div></div>person's是透過多個欄位結合來計算雜湊碼的。都是透過Object

hash

函數來計算。

選擇欄位但哪些欄位是相關的嗎?需求將會幫助我們回答這個問題:如果相等的物件必須具有相同的雜湊碼,那麼計算雜湊碼就不應包括任何不用於相等檢查的欄位。 (否則兩個物件只是這些字段不同但是仍然有可能會相等,此時他們這兩個物件哈希碼卻會不相同。)

所以用於哈希組字段應該相等時使用的字段的子集。預設情況下都使用相同的字段,但有一些細節需要考慮。

一致性

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

正如我们以上所见的哈希码用于确定元素的桶。但如果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性能,所以除非分析表明必要性,否则不要浪费太多的精力。


以上是Java實作hashCode方法的範例程式碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

Java 完美數指南。這裡我們討論定義,如何在 Java 中檢查完美數?

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。這裡我們透過範例討論簡介、如何使用 weka java、平台類型和優點。

Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

Java 史密斯數指南。這裡我們討論定義,如何在Java中檢查史密斯號?帶有程式碼實現的範例。

Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

在本文中,我們保留了最常被問到的 Java Spring 面試問題及其詳細答案。這樣你就可以順利通過面試。

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

Java 中的時間戳至今 Java 中的時間戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的時間戳記到日期指南。這裡我們也結合範例討論了介紹以及如何在java中將時間戳記轉換為日期。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

如何在Spring Tool Suite中運行第一個春季啟動應用程序? 如何在Spring Tool Suite中運行第一個春季啟動應用程序? Feb 07, 2025 pm 12:11 PM

Spring Boot簡化了可靠,可擴展和生產就緒的Java應用的創建,從而徹底改變了Java開發。 它的“慣例慣例”方法(春季生態系統固有的慣例),最小化手動設置

See all articles