先了解什麼是二進制原碼:
二進制中一個字節(byte)是存儲信息的最小單位,大小爲8bits,即8個位,每個0或1就是一個位(bit),規定數據的最高位是符號位。符號位是1表示負數,是0表示正數。正數存儲二進制原碼,負數存儲的是二進制的補碼,補碼是負數的絕對值反碼加1。
8bits = 1byte
byte (1個字節)
char (2個字節)
short (2個字節)
int (4個字節)
long (8個字節)
float (4個字節)
double (8個字節)
看代碼:
public static String bytesHexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String str = Integer.toHexString(b[i] & 0xFF);
if (str.length() == 1) {
str = '0' + str;
}
ret += str.toUpperCase();
}
return ret;
}
函數將byte[] b轉化成十六進制字符串的過程中,for循環中的byte和0xFF進行與運算後使用Integer.toHexString轉化出十六進制字符串。b[i] & 0xFF運算後得出的仍然是int,爲什麼要進行這一步?直接用Integer.toHexString(b[i])將byte強轉爲int行不行?
看例子:
0000 0001代表的是數字1
1000 0000代表的是-1
所以一個byte
正數最大是0111 1111,也就是數字127
負數最大是1111 1111,也就是數字-128
什麼是反碼:
反碼就是把它的原碼除符號位都取反(0變1,1變0)
一個數如果是正數,則它的反碼與原碼相同;
一個數如果是負數,則符號位爲1,其餘各位是對原碼取反
什麼是補碼:
補碼是在反碼的末位上加1,正數的原反補碼是相同的
在計算機中,如果我們用1個字節表示一個數,一個字節有8位,超過8位就進1,
在內存中情況爲(100000000),進位1被丟棄。
- 一個數爲正,則它的原碼、反碼、補碼相同
- 一個數爲負,符號位爲1,其餘各位是對原碼取反,然後整個數加1
例如:
0的原碼爲 00000000 0的反碼爲 11111111(正零和負零的反碼相同)
0的補碼爲 100000000(舍掉開頭的1,正零和負零的補碼相同)
1的原碼爲 10000001
1的反碼爲 11111110
1的補碼爲 11111111
那麼-1的三碼如下:
首先正1的原碼:
0000 0001
然後按位取反(每個位上的0變成1,1變成0):
1111 1110
最後加1:
1111 1111
java採用的是補碼的形式,利用溢出將減法變成加法對於十進制數,從5得到1
用減法:
5-4=1
因爲4+6滿10,我們可以將6作爲4的補數
用加法:
5+6=11(去掉高位1,也就是減10)得到1.
對於十六進制數,從f到5
用減法:
f-a=5
因爲a+6滿16,將6作爲a的補數
用加法:
f+6=15(去掉高位1,也就是減16)得到5.
補充了一些知識點,回到最初的疑問:
當系統檢測到byte可能會轉化成int或者說byte與int類型進行運算的時候,會將byte的內存空間高位補1(也就是按符號位補位)擴充到32位,再參與運算,其二進制補碼其實已經改變了,&0xff可以將高的24位置爲0,低8位保持原樣。這樣做的目的就是爲了保證二進制數據的一致性。
最後一個梨:
-12的二進制表示:
1111 0100
高位補齊1後變成(按符號位補位)
1111 1111 1111 1111 1111 1111 1111 0100
十六進制0xFF的二進制表示是:
1111 1111。
高24位補0(按符號位補位)
0000 0000 0000 0000 0000 0000 1111 1111
-12補碼與0xFF進行與&操作,就是
1111 1111 1111 1111 1111 1111 1111 0100 &
0000 0000 0000 0000 0000 0000 1111 1111
---------------------------------------
0000 0000 0000 0000 0000 0000 1111 0100
最後:byte類型的數字要&0xff再賦值給int類型,其本質原因就是想保持二進制補碼的一致性。