衆所周知,計算機底層是二進制。而java作爲一門計算機編程語言,也對二進制的位運算提供了完整的支持。
在java中,int是32位的,也就是說可以用來實現32位的位運算。方便起見,我們一般用16進制對它賦值,比如: 0011表示成16進制是 0x3, 110111表示成16進制是 0x37。
那麼什麼是位運算呢?位運算是將數據看做二進制,進行位級別的操作。主要有移位運算和邏輯運算
移位運算:
- 左移:操作符爲<<,向左移動,右邊的低位補0,左邊高位捨棄,將二進制看做整數,左移1位就相當於乘以2。
- 無符號右移:操作符爲>>>,向右移動,右邊的捨棄掉,左邊補0。
- 有符號右移:操作符爲>>,向右移動,右邊的捨棄掉,左邊補的值取決於原來最高位,原來是1就補1,原來是0就補0,將二進制看做整數,右移1位相當於除以2。
10進制轉二進制的時候,因爲二進制數一般分8位、 16位、32位以及64位 表示一個十進制數,所以在轉換過程中,最高位會補零。
在計算機中負數採用二進制的補碼錶示,10進制轉爲二進制得到的是源碼,將源碼按位取反得到的是反碼,反碼加1得到補碼
二進制的最高位是符號位,0表示正,1表示負。
例如:
int a = 4; //100 a = a >> 2; //001, System.out.println("4>>2運算的結果是 :" + a);//變爲1 a = 4; //100 a = a << 3; //100000, System.out.println("4<<3運算的結果是 :" + a);//變爲32 System.out.println("16>>2運算的結果是 :" + ((16) >> 2));//變爲4 System.out.println("-16>>2運算的結果是 :" + ((-16) >> 2));//變爲-4 System.out.println("16>>>2運算的結果是 :" + ((16) >>> 2));//變爲4 System.out.println("-16>>>2運算的結果是 :" + ((-16) >>> 2));//變爲大的整數,看是多少位的
得到結果
可見正數做>>>運算的時候和>>是一樣的。區別在於負數運算.
邏輯運算有:
- 按位與 &:兩位都爲1才爲1
- 按位或 |:只要有一位爲1,就爲1
- 按位取反 ~: 1變爲0,0變爲1
- 按位異或 ^ :相異爲真,相同爲假
例如:
int a = ...; a = a & 0x1 // 返回0或1,就是a最右邊一位的值。 a = a | 0x1 //不管a原來最右邊一位是什麼,都將設爲1
我們來看幾個簡單的應用場景:
場景一:判斷奇偶
分析:奇數都不是2的整數倍,轉換成二進制後最低位必然爲1,偶數則相反。利用這個特性我們可以很容易的通過位運算判斷一個整數的奇偶性。
看代碼:
int i = 1;// 二進制存儲方式爲00000000000000000000000000000001 int j = 5;// 二進制存儲方式爲00000000000000000000000000000101 int k = 6;// 二進制存儲方式爲00000000000000000000000000000110 if ((i & j) == 1) { System.out.println("j的最低位爲1,爲奇數"); } if ((i & k) == 0) { System.out.println("k的最低位爲0,爲偶數"); }
場景二:判斷一個正整數是不是2的整數次冪
分析:我們先來看一下常見的2的整數次冪的數:2、4、8、16,轉化成二進制依次爲:10、100、1000、10000,發現規律了沒有?那就是除了首位是1,其他全是0。恰巧這些數減去1後等於他們依次按位取反的結果,比如8-1=7,二進制是111,可以通過8的二進制1000按位取反得到。而8&7=0,提取一下規律就是:
(n&(n-1))==0
符合這個規律的n就是2的整數次冪了。