日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jdk1.8hashmap为什么对hash进行了一次扰动处理

發布時間:2025/5/22 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jdk1.8hashmap为什么对hash进行了一次扰动处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
public V put(K key, V value) {return putVal(hash(key), key, value, false, true); }static final int hash(Object key) {int h;// 判斷key是否為null, 如果為null,則直接返回0;// 如果不為null,則返回(h = key.hashCode()) ^ (h >>> 16)的執行結果return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

我們一步一步來分析

  • 第1步:h = key.hashCode()
"helloWorld".hashCode() --> -1554135584 "123456".hashCode() --> 1450575459 "我愛java".hashCode() --> -1588929438
  • 第2步:h >>> 16
    無符號右移(>>>):
    對于正數的帶符號右移,不論正數還是負數,移位過程中高位均補零。

  • 第3步:h ^ (h >>> 16)

假設h值為:1290846991 它的二進制數為:01001100 11110000 11000011 00001111 右移十六位之后:00000000 00000000 01001100 11110000 進行異或操作后:01001100 11110000 10001100 11110000 最終得到的hash值:1290833136
  • 第四步:計算元素在數組中存放的位置
    由下面這行代碼決定的:
// 將(數組的長度-1)和hash值進行按位與操作: i = (n - 1) & hash // i為數組對應位置的索引 n為當前數組的大小

我們將上面這步操作作為第4步操作,來對比一下執行1、2、3、4四個步驟和只執行第1、4兩個步驟所產生的不同效果。

我們向hashmap中put兩個元素node1(key1, value1)、node2(key2, value2),hashmap的數組長度n=16。

執行1、2、3、4 四個步驟:

  • h = key.hashCode()
    假設計算的結果為:h = 3654061296
    對應的二進制數為: ???01101100 11100110 10001100 11110000
  • h >>> 16
    h無符號右移16位得到: 00000000 00000000 01101100 11100110
  • hash = h ^ (h >>> 16)
    異或操作后得到hash:? 01101100 11110000 11100000 00000110
  • i = (n-1) & hash
    n-1=15 對應二進制數 : ?? 00000000 00000000 00000000 00001111
    hash : ??01101100 11110000 11100000 00000110
    hash & 15 : ?? 00000000 00000000 00000000 00000110
    轉化為10進制 : &ensp 5
    最終得到i的值為5,也就是說node1存放在數組索引為5的位置。
  • 同理我們對(key2, value2) 進行上述同樣的操作過程:

  • h = key.hashCode()
    假設計算的結果為:h = 3652881648
    對應的二進制數為: ???01101100 11011101 10001100 11110000
  • h >>> 16
    h無符號右移16位得到: 00000000 00000000 01101100 11011101
  • hash = h ^ (h >>> 16)
    異或操作后得到hash:? 01101100 11110000 11100000 00101101
  • i = (n-1) & hash
    n-1=15 對應二進制數 : ?? 00000000 00000000 00000000 00001111
    hash : ??01101100 11110000 11100000 00101101
    hash & 15 : ??00000000 00000000 00000000 00001101
    轉化為10進制 : &ensp 13
    最終得到i的值為13,也就是說node2存放在數組索引為13的位置
  • 執行1、4兩個步驟:

  • h = key.hashCode()
    計算的結果同樣為:h = 3654061296
    對應的二進制數為: ???01101100 11100110 10001100 11110000
  • i = (n-1) & hash
    n-1=15 對應二進制數 : ?? 00000000 00000000 00000000 00001111
    hash(h) : ??01101100 11100110 10001100 11110000
    hash & 15 : ??00000000 00000000 00000000 00000000
    轉化為10進制 : ? 0
    最終得到i的值為0,也就是說node1存放在數組索引為0的位置
  • 同理我們對(key2, value2) 進行上述同樣的操作過程:

  • h = key.hashCode()
    計算的結果同樣為:h = 3652881648
    對應的二進制數為: ???01101100 11011101 10001100 11110000
  • i = (n-1) & hash
    n-1=15 對應二進制數 : ?? 00000000 00000000 00000000 00001111
    hash(h) : ??01101100 11110000 11100000 11110000
    hash & 15 : ??00000000 00000000 00000000 00000000
    轉化為10進制 : ? 0
    最終得到i的值為0,也就是說node2同樣存放在數組索引為0的位置
  • 相信大家已經看出區別了:

    ????當數組長度n較小時,n-1的二進制數高16位全部位0,這個時候如果直接和h值進行&(按位與)操作,那么只能利用到h值的低16位數據,這個時候會大大增加hash沖突發生的可能性,因為不同的h值轉化為2進制后低16位是有可能相同的,如上面所舉例子中:key1.hashCode() 和key2.hashCode() 得到的h值不同,一個h1 = 3654061296 ,另一個h2 = 3652881648,但是不幸的是這h1、h2兩個數轉化為2進制后低16位是完全相同的,所以h1 & (n-1)和 h2 & (n-1) 會計算出相同的結果,這也導致了node1和node2 存儲在了數組索引相同的位置,發生了hash沖突。

    ? 當我們使用進行 h ^ (h >>> 16) 操作時,會將h的高16位數據和低16位數據進行異或操作,最終得出的hash值的高16位保留了h值的高16位數據,而hash值的低16數據則是h值的高低16位數據共同作用的結果。所以即使h1和h2的低16位相同,最終計算出的hash值低16位也大概率是不同的,降低了hash沖突發生的概率。

    ? ps:這里面還有一個值的注意的點: 為什么是(n-1)?

    我們知道n是hashmap中數組的長度,那么為要進行n-1的操作?答案同樣是為了降低hash沖突發生的概率!

    要理解這一點,我們首先要知道HashMap規定了數組的長度n必須為2的整數次冪,至于為什么是2的整數次冪,會在HashMap的擴容方法resize()里詳細講。

    既然n為2的整數次冪,那么n一定是一個偶數。那么我們來比較i = hash & n和 i = hash & (n-1)有什么異同。

    n為偶數,那么n轉化為2進制后最低位一定為0,與hash進行按位與操作后最低位仍一定為0,這就導致i值只能為偶數,這樣就浪費了數組中索引為奇數的空間,同時也增加了hash沖突發生的概率。

    所以我們要執行n-1,得到一個奇數,這樣n-1轉化為二進制后低位一定為1,與hash進行按位與操作后最低位即可能位0也可能位1,這就是使得i值即可能為偶數,也可能為奇數,充分利用了數組的空間,降低hash沖突發生的概率。

    總結

    以上是生活随笔為你收集整理的jdk1.8hashmap为什么对hash进行了一次扰动处理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。