標籤:
前天幾天研究了下JDK的Collection介面,本來準備接著研究Map介面,可是一查看HashMap類源碼傻眼咯,到處是位元運算實現,所以我覺得還是有必要先補補位元運算知識,不然代碼看起來有點費力。今天系統研究了下,現記錄如下。
首先要明白一個概念,Java位元運算是針對於整型資料類型的二進位進行的移位操作。主要包括位與、位或、位非,有符號左移、有符號右移,無符號右移等等。需要注意一點的是,不存在無符號左移<<<運算子。根據位元運算的概念規定,我們首先需要弄明白兩個問題,java有哪些資料類型是整數資料型別和各數字進位之間轉換問題。Java整數資料型別有:byte、char、short、int、long。要把它們轉換成二進位的原碼形式,必須明白他們各占幾個位元組。我們都知道,一個位元組佔8位。
資料類型 所佔位元
byte 8
boolean 8
short 16
int 32
long 64
float 32
double 64
char 16
還需要明白一點的是:電腦表示數字正負不是用+ -加減號來表示,而是用最高位元字來表示,0表示正,1表示負
所以比如-4用二進位原碼錶示就是1111 1111 1111 1111 1111 1111 1111 1100
下面根據執行個體一個一個的來說明各種位元運算的運算規則:
位與&(真真為真 真假為假 假假為假)
4&6
0000 0000 0000 0000 0000 0000 0000 0100
0000 0000 0000 0000 0000 0000 0000 0110
0000 0000 0000 0000 0000 0000 0000 0100
結果:4
位或|(真真為真 真假為真 假假為假)
4|6
0000 0000 0000 0000 0000 0000 0000 0100
0000 0000 0000 0000 0000 0000 0000 0110
0000 0000 0000 0000 0000 0000 0000 0110
結果:6
位非~(取反碼)【註:Java中正數的最高位為0,負數最高位為1,即最高位決定正負符號】
~4
0000 0000 0000 0000 0000 0000 0000 0100
1111 1111 1111 1111 1111 1111 1111 1011
解碼:先取反碼,再補碼
0000 0000 0000 0000 0000 0000 0000 0100
0000 0000 0000 0000 0000 0000 0000 0101
結果:-5
位異或^(真真為假 真假為真 假假為假)
4^6
0000 0000 0000 0000 0000 0000 0000 0100
0000 0000 0000 0000 0000 0000 0000 0110
0000 0000 0000 0000 0000 0000 0000 0010
結果:2
有符號右移>>(若正數,高位補0,負數,高位補1)
-4>>2
1111 1111 1111 1111 1111 1111 1111 1100 原碼
1111 1111 1111 1111 1111 1111 1111 1111 右移,最左邊空出兩位按規則負數空位補1
0000 0000 0000 0000 0000 0000 0000 0000 解碼
0000 0000 0000 0000 0000 0000 0000 0001 補碼(補碼即最後一位+1)
結果:-1
有符號左移<<(若正數,高位補0,負數,高位補1)
-4<<2
1111 1111 1111 1111 1111 1111 1111 1100 原碼
1111 1111 1111 1111 1111 1111 1111 0000 左移,最右邊空出兩位補0
0000 0000 0000 0000 0000 0000 0000 1111 解碼
0000 0000 0000 0000 0000 0000 0001 0000 補碼
結果:-16
無符號右移>>>(不論正負,高位均補0)
-4>>>2
1111 1111 1111 1111 1111 1111 1111 1100 原碼
0011 1111 1111 1111 1111 1111 1111 1111 右移(由於高位均補0,故>>>後的結果一定是正數)
結果:1073741823
由於資料類型所佔位元組是有限的,而位移的大小卻可以任意大小,所以可能存在位移後超過了該資料類型的表示範圍,於是有了這樣的規定:
如果為int資料類型,且位移位元大於32位,則首先把位移位元對32模數,不然位移超過總位元沒意義的。所以4>>32與4>>0是等價的。
如果為long類型,且位移位元大於64位,則首先把位移位元對64模數,若沒超過64位則不用對位元模數。
如果為byte、char、short,則會首先將他們擴充到32位,然後的規則就按照int類型來處理。
學到這裡,我想你也可能會問,位元運算到底有什麼用途或者有哪些情境可以應用到它。因為位元運算的運算效率比直接對數字進行加減乘除高很多,所以當出現以下情景且對運算效率要求較高時,可以考慮使用位元運算。不過實際工作中,很少用到它,我也不知道為什麼很少有人用它,我想應該是它比較晦澀難懂,如果用它來進行一些運算,估計編寫的代碼的可讀性會不強,畢竟我們寫的代碼不僅僅留給自己一個人看。
1. 判斷int型變數a是奇數還是偶數
a&1 = 0 偶數
a&1 = 1 奇數
2. 求平均值,比如有兩個int類型變數x、y,首先要求x+y的和,再除以2,但是有可能x+y的結果會超過int的最大表示範圍,所以位元運算就派上用場啦。
(x&y)+((x^y)>>1);
3. 對於一個大於0的整數,判斷它是不是2的幾次方
((x&(x-1))==0)&&(x!=0);
4. 比如有兩個int類型變數x、y,要求兩者數字交換,位元運算的實現方法:效能絕對高效
x ^= y;
y ^= x;
x ^= y;
5. 求絕對值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ; //or: (x+y)^y
}
6. 模數運算,採用位元運算實現:
a % (2^n) 等價於 a & (2^n - 1)
7. 乘法運算 採用位元運算實現
a * (2^n) 等價於 a << n
8. 除法運算轉化成位元運算
a / (2^n) 等價於 a>> n
9. 求相反數
(~x+1)
10 a % 2 等價於 a & 1
等等
當然還有牛人使用位元運算來實現許可權控制,加密技術,裡面的奧秘深不可測啊!哈哈。
原文串連: http://www.52ij.com/jishu/102.html
Java位元運算總結:位元運算用途廣泛《轉》