byte存儲范圍,表示范圍
我們知道byte代表1個字節,數據存儲的范圍:[0x00, 0xFF]。byte變量表示值的范圍:[-128, 127]。
下面這段代碼並不是輸出128,而是輸出-128,因為byte變量表示值的范圍為[-128, 127]。128剛剛好超出上界127有1單位,溢出為-128。
300對應byte值也不是300,而是按byte長度(1字節)截取存儲內容后的值。
可以看到,300 = 0b100101100,截取1byte長度后,值為0b00101100,也就有 b = 0b00101100 => b = 44
byte b = (byte) 128;
System.out.println(b); // 輸出-128
byte b = (byte) 300; // 300 = 0b100101100, b = 0b101100
System.out.println(b); // 輸出44
byte位運算
還有一種比較有意思的現象,就是byte位運算,中間過程是否進行類型轉換,也會影響結果。
請看下面的代碼,分別打印出什么?(i1, i2):
byte a = (byte)0xFF;
int i1 = 0xFF & a;
int i2 = a;
System.out.println(i1); // 打印255
System.out.println(i2); // 打印-1
運行程序,發現打印i1 為255,打印i2為-1,同樣的byte類型變量a = 0xFF,如果直接轉換為int類型,值為-1;如果與0xFF先進行按位與運算,值為255。
中間只是對a和0xFF進行了與運算,而a本身寬1字節,但打印結果卻不同,這是為什么呢?
猜測是不是跟運算過程中的類型轉換有關。下面先做驗證:
- 全部顯式轉換為byte類型,再 &;
- 全部顯式轉換為int類型,再&;
byte a = (byte)0xFF;
int i1 = 0xFF & a;
int i2 = a;
int i3 = (byte)0xFF & (byte)a;
int i4 = (int)0xFF & (int)a;
System.out.println(i1); // 打印255
System.out.println(i2); // 打印-1
System.out.println(i3); // 打印-1
System.out.println(i4); // 打印255
根據打印結果,可以得出結論:
1. byte型數據跟int型數據進行運算時,會先默認轉換為int類型。(類型提升)
2. byte -> int直接類型轉換,並不能改變數的符號。
byte型位運算為何結果不同於int型位運算?
int和byte都可以表示負數,為什么轉換為int進行 & ,與轉換為byte進行&,為何結果不一樣?
由結論2,知因為int i4 = (int)0xFF & (int)a;
中的類型轉換(int)並不會改變符號,那么是什么時候改變的呢? 只可能是與0xFF進行&時,改變了a的符號。因為結果是255,但byte a = -1,而i2 = a值也是-1。
詳細分析知,0xFF是1byte,而int是2byte。
由於a是int類型,4byte存儲,實際a存儲值 = 補碼(a) = 反碼(-a) + 1 = 反碼(1) + 1 = ~0b0000 0000 0000 0000 0000 0000 0000 0001 + 1 = 0b1111 1111 1111 1111 1111 1111 1111 1111 = 0xFFFF FFFF
可知,
int i4 = 0xFF & (int)a
= 0xFF & -1
= 0xFF & 0xFFFF FFFF
= 0xFF,符號位為0,是正數
=> i4 = 255
不妨將0xFF改成成0xFFFFFFFF,來驗證上面的猜測:
byte a = (byte)0xFF;
...
int i4 = (int)0xFF & (int)a;
int i5 = 0xFFFFFFFF & a;
...
System.out.println(i4); // 打印255
System.out.println(i5); // 輸出-1
可以得到i5 = -1,符合猜測預期。 因此,需要十分注意類型轉換過程中值的變化,還有位寬的變化,特別是涉及到負數,因為計算機中存儲的是補碼,就會涉及到符號位。