1. 程式人生 > >關於 hashCode() 你需要了解的 3 件事

關於 hashCode() 你需要了解的 3 件事

二、雜湊碼衝突

 

任何時候,兩個不同物件有相同的雜湊碼,我們稱之為衝突。衝突不要緊,它只是意味著有多個物件在同一個空間裡,所以 HashMap 會再檢查一遍來找正確的物件。大量的衝突將會降低系統的效能,但是它們不會導致錯誤的結果。

 

但是如果你誤認為雜湊碼是一個物件唯一的控制代碼,例如使用它作為Mapkey,你有時會得到錯誤的物件。因為雖然衝突很罕見,但他們是不可避免的。例如,字元“Aa”“BB”產生相同的雜湊碼:2112。因此:

 

2. 永遠不要把雜湊碼誤用作一個key

 

你可能會反對,不像印表機的型別例子,在

Java 中,有 4,294,967,296 的空間(2^32 個可能的整型值)。40億的插槽,發生衝突似乎是極不可能的對嗎?

 

事實證明它不是不太可能。這是令人驚訝的衝突:請想象一下在一個房間裡有 23 個隨機的人。你覺得兩個人是同一天生日的機率有多大 ?很低,因為一年有 365 天嗎?事實上,機率是 50% 左右!50 個人是保守的估計。這個現象稱為生日悖論。應用到雜湊碼,這意味著在 77163 個不同的物件中,有 50% 的可能性發生衝突假設你有一個理想的雜湊的函式,均勻地把物件分佈在所有可用的空間裡面。

 

例如:

安然公司的電子郵件集包含 520,924

封電子郵件。計算電子郵件內容字串的雜湊碼時,我發現 50 對(甚至是 2 個三元組)不同的電子郵件有著相同的雜湊碼。對於五十萬個字串,這是一個很好的結果。但是這裡的資訊是:如果你有很多資料元素,衝突就會發生。如果你正在使用雜湊碼作為 key,你不會立即注意到你的錯誤。但是少數人會收到錯誤的郵件。

 

三、雜湊碼可變

最後,在雜湊碼的契約中,有一個很重要的細節是相當讓人吃驚的:hashCode 並不保證在不同的應用執行中得到相同的結果。讓我們看一看 Java 文件:

 

在一次 Java 應用的執行中,對於同一個物件,hashCode 方法必須始終返回相同的整數,但這整數不反映物件是否被修改(

equals 比較)的資訊。同一個應用的不同執行,該整數不必保持一致。

 

事實上,這是不常見的,一些類庫中的類甚至指定它們用於計算雜湊碼的精確公式(例如字串)。對於這些類,雜湊碼總是會相同。雖然大部分的雜湊碼的實現提供穩定的值,但你不能依賴於這一點。正如這篇文章指出的,有些類庫在不同程序中會返回不同的雜湊值,這有的時候會讓人困惑。谷歌的 Protocol Buffers 就是一個例子。

 

因此,你不應該在分散式應用程式中使用雜湊碼。一個遠端物件可能與本地物件有不同的雜湊碼,即使這兩個物件是相等的。

 

3. 在分散式應用中不要使用雜湊碼

 

此外,你應該意識到從一個版本到另一個版本雜湊碼的功能實現可能會更改。因此您的程式碼不應該依賴於任何特定的雜湊碼值。例如,你不應該使用雜湊碼來持久化狀態。下次你執行程式的時候,相同物件的雜湊碼可能不同。

最好的建議可能是:完全不使用雜湊碼,除非你自己創造了基於雜湊的演算法。

 

一種替代方法:SHA1

你可能知道加密的雜湊碼 SHA1 有時被用來標識物件(例如,git這樣做)。這也是不安全嗎?不。SHA1 使用 160 位金鑰,這使得衝突幾乎是不可能的。即使有很多物件,在這個空間發生衝突的機率遠遠低於一顆流星撞到你正在執行程式的電腦的機率。這篇文章對衝突的概率作了很好的概述。

 

關於雜湊碼應該還有其他可談的,但這些看起來是最重要的。如果我有什麼遺漏,歡迎告訴我。

 

 

本教程由尚矽谷教育大資料研究院出品,如需轉載請註明來源。