簡體   English   中英

為什么以下三個字符串的哈希碼相同?

[英]Why the following three strings's hashcode are same?

在閱讀了JDK的源代碼之后,我仍然驚訝於字符串"AaAa", "AaBB" and "BBBB"具有相同的哈希碼。

JDK的來源如下:

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;

任何人都可以澄清嗎?

因為這就是定義要為String計算哈希碼的方式

字符串對象的哈希碼計算為

 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 

所以:

  • 對於AaAa65*31^3 + 97*31^2 + 65*31 + 97 = 2031744
  • 對於AaBB65*31^3 + 97*31^2 + 66*31 + 66 = 2031744
  • 對於BBBB66*31^3 + 66*31^2 + 66*31 + 66 = 2031744

因為概率

可能有大約40億個哈希碼( Integer.MIN_VALUE -> Integer.MAX_VALUE )和基本上無限的字符串。 必然會有碰撞 實際上, 生日問題向我們顯示任意碰撞的可能性很高,僅需要〜77,000個字符串 -如果哈希函數具有極高的熵,而事實並非如此,那就行了。

也許您在考慮加密散列函數

對消息進行很小的更改就應該廣泛更改哈希值,以使新的哈希值看起來與舊的哈希值不相關

在這種情況下, Object.hashCode並非設計用於加密目的。

另請參見Java的hashCode()有多安全?

他們的哈希碼是

AaAa: ((65 * 31 + 97) * 31 + 65) * 31 + 97 = 2.031.744
AaBB: ((65 * 31 + 97) * 31 + 66) * 31 + 66 = 2.031.744
BBBB: ((66 * 31 + 66) * 31 + 66) * 31 + 66 = 2.031.744

這就是數學的方式,沒什么可混淆的。
請注意,97和66之間恰好是31的區別,這就是使這些哈希碼排列得如此好的原因。

這是來自Java文檔中的Object#hashCode方法的描述:

在Java應用程序執行期間,只要在同一對象上多次調用它, hashCode方法就必須一致地返回相同的整數,前提是不修改該對象的equals比較中使用的信息。此整數不必與一個整數保持一致一個應用程序的執行到同一應用程序的另一個執行。

如果根據equals(Object)方法,兩個對象相等,則在兩個對象中的每個對象上調用hashCode方法必須產生相同的整數結果。

根據java.lang.Object#equals(java.lang.Object)方法,如果兩個對象不相等,則不需要在兩個對象中的每個對象上調用hashCode方法必須產生不同的整數結果。 但是,程序員應該意識到,為不相等的對象生成不同的整數結果可能會提高哈希表的性能。

因此, String類的實現也保持了上述特征。這是正常現象。

有幾種類型的哈希函數具有不同的設計和性能標准。

  1. 用於索引的哈希函數(例如關聯數組和類似用法)可能會發生頻繁沖突而不會出現問題,因為哈希表代碼將隨后以某種名稱處理該代碼,例如將其放入列表或重新哈希。 這就是時間的性能。 Java hash()似乎是這種類型的

  2. 另一類函數,例如SHA *等加密哈希,以哈希性能為代價,努力避免沖突。

  3. 第三種散列函數是密碼驗證器散列,密碼散列被設計為非常慢(通常為100毫秒左右),並且可能需要大量內存,因此不會出現頻繁沖突。 這里的目的是要使蠻力攻擊花費盡可能長的時間以至於不可行。

根據用途選擇哈希的類型和特征。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM