雖然現在很少用到二進制,可是一些源碼中會經常遇到,比如:
//HashMap中的hash方法:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
這裏記錄一些二進制知識。
一:負數如何顯示其二進制。
比如5的二進制數爲:00000000 00000000 00000000 00000101(int 類型佔用4個字節,每個字節8位).
那麼-5的二進制是多少了。對於負數,這裏需要理解反碼和補碼。
1、所謂原碼就是二進制定點表示法,即最高位爲符號位,“0”表示正,“1”表示負,其餘位表示數值的大小。
2、反碼錶示法規定:正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外。
原碼10010= 反碼11101 (10010,1爲符號碼,故爲負)
(11101) 二進制= -13 十進制
3、補碼錶示法規定:正數的補碼與其原碼相同;負數的補碼是在其反碼的末位加1。
舉一例,我們來看整數-5在計算機中如何表示。
假設這也是一個int類型,那麼:
1、先取1的原碼:00000000 00000000 00000000 00000101
2、得反碼: 11111111 11111111 11111111 11111010
3、得補碼: 11111111 11111111 11111111 11111011
可以在控制檯輸出測試:
輸出-5的二進制數
System.out.println(Integer.toBinaryString(-5));// 11111111 11111011
二:二進制常用的運算。(^異或運算,與運算&,|運算,左移運算<<,右移運算(有符號)>>,無符號又移>>>)
1.^異或運算。二進制數 相同爲0.不同爲1;
/**
* ^異或運算。二進制數 相同爲0.不同爲1;
*/
@Test
public void testOr(){
int first=3;// 0011------------3
int second=4;// 0100------------4
int three=first^second;// 0111------------7
System.out.println(three);//7
}
2.&運算。只有都爲1時才爲1.否則爲0
@Test
/**
* 二進制數 只有都爲1時才爲1.否則爲0
*/
public void testAnd(){
int first=12;//-----------------00001100 值爲 12
int second=22;//----------------00010100 值爲 22
int three=first&second;//-------00000100 值爲 4
System.out.println(three);//---4
}
3.|運算。(參加運算的兩個對象只要有一個爲1,其值爲1。)
@Test //(參加運算的兩個對象只要有一個爲1,其值爲1。)
public void testOrAnd(){
System.out.println(5|2);//7
System.out.println(Integer.toBinaryString(5));// 00000000 00000000 00000000 00000101
System.out.println(Integer.toBinaryString(2));// 00000000 00000000 00000000 00000010
System.out.println(Integer.toBinaryString(7));// 00000000 00000000 00000000 00000111
}
4.左移運算(<<)
如果是整數,直接轉爲二進制數進行左移,低位補0.
如果是負數。首先也要轉爲二進制數(通過反碼,補碼機制)。轉移完後,將二進制數加一,取反碼。得最終的結果
下面給的例子是 -5<< 結果爲20.
/**
* 左移運算(<<) 二進制數向左移動,低位用0補齊
* 反碼是除符號位(最高位)外取反
*/
@Test
public void testLeftMove(){
int first=33;// 00100001 值爲33
int two=first<<2;// 10000100 值爲132
System.out.println(two); //132
//如果是負數
//-5 的二進制,先是算5 的二進制 00000000 00000000 00000000 00000101 然後進行取反(除最高位外)
//-5的反碼是 11111111 11111111 11111111 11111010
// 補碼 反碼+1 11111111 11111111 11111111 11111011
//-----------------------------------計算 -5<<2的值----------------------------
//首先-5的補碼左移兩位,低位補0得:
// 11111111 11111111 11111111 11101100
//然後 減一得:
// 11111111 11111111 11111111 11101011
//最後取反即可:
// 00000000 00000000 00000000 00010100 值爲20
System.out.println(-5<<2);//20
System.out.println(Integer.toBinaryString(-5));//11111111 11111111 11111111 11111011
}
5.右移運算(>>).如果是正數,高位補0.如果是負數,高位補1。
都是先轉換爲二進制再進行位移運算。如果是負數,也是要藉助反碼和補碼。
/**
* 右移(>>) 二進制數整體向右移動。如果是正數,高位補0.如果是負數,高位補1
*/
@Test
public void testRightMove(){
//-5的二進制 11111111 11111111 11111111 11111011
//右移1位 11111111 11111111 11111111 111111101
System.out.println(-5>>1);//-3
System.out.println(Integer.toBinaryString(-3));//11111111111111111111111111111101
System.out.println(-2147483647>>5);
System.out.println(Integer.toBinaryString(-2147483647>>5));
System.out.println(Integer.toBinaryString(-2147483647));
}
6.無符號的右移運算(>>>)
即無論是正數還是負數,高位都補0.
下面代碼可見>>>運算不再採用補碼和反碼機制了。不管是正數還是負數,最終都是正數。所以直接 將轉移後的二進制轉換爲正數。如果是負數採用>>>的話,也爲正數了。
/**
* 無論正負高位同一補0。
*/
@Test
public void testRightMoveThree(){
System.out.println(-5>>>2); //1073741822
System.out.println(Integer.toBinaryString(-5)); //11111111 11111111 11111111 11111011
System.out.println(Integer.toBinaryString(1073741822));// 00111111 11111111 11111111 11111110
}