我們平時在寫**過程中用的位運算操作比較少,因為我們更關注於可讀性而不是效能,如果為了效能而使用較多的位運算,我想我們的同事會瘋掉。但在框架里位運算卻非常常見,因為框架的效能是我們關注的點。下面就來一起回顧一下常見的位運算操作:
<< : 左移運算子,num << 1,相當於num乘以2 低位補0
>> : 表示右移,如果該數為正,則高位補 0,若為負數,則高位補 1。
>>> : 表示無符號右移,也叫邏輯右移,即若該數為正,則高位補 0,而若該數為負數,則右移後高位同樣補 0。
% : 模運算 取餘
^ : 位異或 第乙個運算元的的第n位於第二個運算元的第n位相反,那麼結果的第n為也為1,否則為0
& : 與運算 第乙個運算元的的第n位於第二個運算元的第n位如果都是1,那麼結果的第n為也為1,否則為0
| : 或運算 第乙個運算元的的第n位於第二個運算元的第n位 只要有乙個是1,那麼結果的第n為也為1,否則為0
~ : 非運算 運算元的第n位為1,那麼結果的第n位為0,反之,也就是取反運算(一元操作符:只操作乙個數)
static
final
inthash
(object key)
此時我們心中會有兩個疑惑:
來看這樣乙個例子:
將 h 無符號右移 16 為相當於將高區 16 位移動到了低區的 16 位,再與原 hashcode 做異或運算,可以看作是將高低位二進位制特徵混合起來
。
從上圖中可以看出,高位的 16 位與原 hashcode 相比沒有發生變化,低位的 16 位發生了變化。
上面的 (h = key.hashcode ()) ^ (h >>> 16) 進行運算後,可以把高區與低區的二進位制特徵混合到低區,那麼為什麼要這麼做呢?
我們要知道,上面計算出來的hashcode值接下來要參與到hashmap中陣列槽位的計算,其計算公式是:(n - 1) & hash,現在假設陣列槽位大小是16,那麼槽位計算過程如下:
觀察可以看出,如果我們不做剛才移位異或運算,那麼在計算槽位時將丟失高區特徵。也許你可能會說,即使丟失了高區特徵,不同 hashcode 也可以計算出不同的槽位來,但是細想當兩個雜湊碼很接近時,那麼這高區的一點點差異就可能導致一次雜湊碰撞,所以這也是將效能做到極致的一種體現。
異或運算能更好的保留各部分的特徵,如果採用 & 運算計算出來的值會向 1 靠攏,採用 | 運算計算出來的值會向 0 靠攏。
這裡假設槽位數不是 16,而是 17,那麼槽位計算公式就變成:(17 - 1) & hash。
可以看出計算結果將會大大趨同,hashcode 參加 & 運算後被更多位的 0 遮蔽,計算結果只剩下兩種,分別是0 和 16,這對於 hashmap 來說是一種災難。
hashmap當中運用了很多精巧的位運算操作,這對於提高效能有很大幫助,更多的,很多的優化點,最終目的還是為了讓雜湊後的結果更均勻的分部,減少雜湊碰撞,提公升 hashmap 的執行效率。
[1]
[2]
[3]
異或運算 HashMap位運算你可知一二
我們平時在寫 過程中用的位運算操作比較少,因為我們更關注於可讀性而不是效能,如果為了效能而使用較多的位運算,我想我們的同事會瘋掉。但在框架里位運算卻非常常見,因為框架的效能是我們關注的點。下面就來一起回顧一下常見的位運算操作 左移運算子,num 1,相當於num乘以2 低位補0 表示右移,如果該數為...
hashmap之位運算
通過以下 開始 static final inttablesizefor int cap 或等於 這個符號比較少見,但是 應該都見過,看到這你應該明白了。例如 a b 可以轉成 a a b。假設 n 的值為 0010 0001,則該計算如下圖 hashmap 的容量必須是 2 的 n 次方,這是為什...
C語言位運算你真的懂Ta麼
c語言的位運算?這是個什麼鬼,哈哈,猶記得我第一次見到c語言的位運算子的時候還以為這是c 程式的輸入輸出流呢,結果後頭才曉得這兩貨除了在c 裡面有表示輸入輸出流還有位運算的意思。一 什麼是位運算?說道位運算就不得不提到乙個概念就是計算機的一切一切都是基於0和1。例如 乙個十進位制數24它的二進位制數...