問題起源
int有幾位言询?hashmap內(nèi)部進(jìn)行hash算法的時候,對高16位和低16位如何處理傲宜?
分析
帶著這個問題运杭,又重新看了一下hashmap的源碼。
下面是函卒,jdk1.8里面hashmap的hash算法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
這段代碼中包含了幾個基礎(chǔ)的知識辆憔,大學(xué)的時候?qū)W過,工作中極少用到报嵌,所以印象已經(jīng)不是很深刻了:
- int 字符
- 位移運(yùn)算符 >>>
- 異或表達(dá)式 ^
解答
為了加深認(rèn)識虱咧,使用如下代碼進(jìn)行驗(yàn)證
public static void main(String[] args) {
System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.MAX_VALUE);
System.out.println(Math.pow(2,31)-1);
int h = 2147483640;
int high = h>>>16;
System.out.println("h的值:"+h);
System.out.println("h高16位的值:"+high);
System.out.println("h負(fù)值的二進(jìn)制:"+Integer.toBinaryString((-1)*h));
System.out.println("h的二進(jìn)制:"+Integer.toBinaryString(h));
System.out.println("h高16位的二進(jìn)制:"+Integer.toBinaryString(high));
System.out.println("h跟高16位進(jìn)行異或運(yùn)算,相當(dāng)于h的低16位跟高16位異或之后作為h的低16位:"+Integer.toBinaryString(h^high));
// System.out.println(Integer.toBinaryString(h&high));
// System.out.println(Integer.toBinaryString(h|high));
// System.out.println(Integer.toBinaryString(h^0));
System.out.println("-1的二進(jìn)制:"+Integer.toBinaryString(-1));
System.out.println("-2的二進(jìn)制:"+Integer.toBinaryString(-2));
System.out.println("-2147483648的二進(jìn)制:"+Integer.toBinaryString(-2147483648));
}
運(yùn)行結(jié)果如下:
-2147483648
2147483647
2.147483647E9
h的值:2147483640
h高16位的值:32767
h負(fù)值的二進(jìn)制:10000000000000000000000000001000
h的二進(jìn)制:1111111111111111111111111111000
h高16位的二進(jìn)制:111111111111111
h跟高16位進(jìn)行異或運(yùn)算锚国,相當(dāng)于h的低16位跟高16位異或之后作為h的低16位:1111111111111111000000000000111
-1的二進(jìn)制:11111111111111111111111111111111
-2的二進(jìn)制:11111111111111111111111111111110
-2147483648的二進(jìn)制:10000000000000000000000000000000
從上可以得出以下結(jié)論:
- 1腕巡、int是32位,從左開始的第一位是符號位血筑,0代表正數(shù)绘沉,1代表負(fù)數(shù)。這樣二進(jìn)制表示正數(shù)的時候豺总,最多是31位车伞,所以int最大值是個奇數(shù)。而負(fù)數(shù)一定是32位且第一位是1喻喳,并且-1是32位1另玖,為什么是這樣?可以這樣理解表伦,-1+1=0谦去,所以32位1加1后剛好變成32位0等于0,負(fù)數(shù)最大值是1接31位0蹦哼,一定是個偶數(shù)哪轿,因?yàn)槿绻兂?,需要加上(31位1+1)翔怎。
- 2窃诉、位移運(yùn)算符杨耙,>>> 等同于 >> ,如 >>16 代表往右移16位飘痛,相當(dāng)于舍棄了低16位珊膜,同理 <<16 代表往左移16位,相當(dāng)于舍棄了高16位宣脉,當(dāng)然位移操作是不會改變原值的车柠。(位移還可以這么理解:>>1,往右移動一位塑猖,我們知道十進(jìn)制往右移動一位相當(dāng)于除以10竹祷,那二進(jìn)制往右移動一位就相當(dāng)于除以2,同理>>3羊苟,往右移動3位塑陵,相當(dāng)于除以8,以此類推)
- 3蜡励、異或(^)操作令花,按位對比,相同的得0凉倚,不同的得1(異或可以這么理解兼都,有差異的用或運(yùn)算,所以0,1或者1,0或運(yùn)算都是1)稽寒,最終的長度跟最長的數(shù)字一樣長扮碧。另外或運(yùn)算(|)是有1得1,最終長度也是跟最長的數(shù)字一樣杏糙。與運(yùn)算(&)是有0得0慎王,最終長度跟最短的數(shù)字一樣長。注意搔啊,不管哪種運(yùn)算,都不能將高位補(bǔ)0補(bǔ)到32位再去運(yùn)算北戏,高位為0的位就相當(dāng)于空负芋,不參與運(yùn)算。