Java對byte 的 + - * / >> >>> << & | ^ (加,減,乘,除,右移,左移,無符號右移,位與,位或,位異或)操作,均會是首先將byte轉化為int, 再行運算。這一事實可能導致多種問題:
假設我們想進行如下byte運算: 1111 1000 右移1位,再與0000 0001 或運算,得 0111 1101。
直覺寫程序如下:
byte b = 0xf8;
byte b2 = b >> 1 | 0x01;
這個寫法里有多重錯誤,現逐個糾正:
1 編譯器報錯,int無法直接自動轉化為byte
為解決此問題,加強制轉化。
byte b = (byte)0xf8;
byte b2 = (byte)( (b >> 1) | 0x01);
2 輸出為 1111 1101 不是我們想要的 0011 1101
原因是>> 是有符號右移,當符號位為1時,左側補的是1而非0。
修改為使用 >>> 無符號右移:
byte b = (byte)0xf8;
byte b2 = (byte)( (b >>> 1) | 0x01);
3 運行后發現輸出依然為 1111 1101
原因是byte在運算前先轉化為int再行位運算,因此分解后的運算步驟如下:
b 轉化為int 1111 1000 轉化為 11111111 11111111 11111111 11111000
無符號右移1位 01111111 11111111 11111111 11111100
與 0x01 按位或 01111111 11111111 11111111 11111101
強制轉化回byte 11111101
解決方案,在右移運算前先 位與 0xff
byte b = (byte)0xf8;
byte b2 = (byte)( ((b & 0xff )>>> 1) | 0x01); //注意必須加括號,因為 >>> 的優先級高於 &
4 運行后發現輸出為我們想要的結果 0111 1101。運算步驟分解如下:
b 轉化為int 1111 1000 轉化為 11111111 11111111 11111111 11111000
和0xff 進行 & 操作 00000000 00000000 00000000 11111000
無符號右移1位 00000000 00000000 00000000 01111100
與 0x01 按位或 00000000 00000000 00000000 01111101
強制轉化回byte 01111101
5 關於System.out.println();
byte b = (byte)0xf8;
System.out.println(b); --最終輸出為-8
運算步驟為:
b 轉化為int 1111 1000 轉化為 11111111 11111111 11111111 11111000
取符號位 - -1111111 11111111 11111111 11111000
取返+1(因為是按補碼運算) -0000000 00000000 00000000 00001000
輸出 -8
最終結論:
1 區分使用 >> 和 >>>
2 在 >> 操作前要首先 & 0xff
3 注意符號優先級,正確使用括號。
4 需要強烈注意的一點是 & 的優先級小於 + . 因此 a = b & 0xff + 2000 的結果 可能不是你想要的
附:
打印byte,int 每個bit值的函數。
public static void printByte(byte b){
for(int i = 7; i >=0 ; i --){
int shiftleft = (b >> i) & 0x01;
System.out.print(shiftleft);
}
System.out.println();
}
public static void printInt(int b){
for(int i = 31; i >=0 ; i --){
int shiftleft = (b >> i) & 0x01;
System.out.print(shiftleft);
}
System.out.println();
}