Java中的補零擴充套件和補符號位擴充套件
https://www.cnblogs.com/DarrenChan/p/6838771.html
今天,魏屌出了一道題,題目如下:
定義一個大頭序的byte[]a={-1,-2,-3,-4},轉換成short[]b.問b[0]和b[1]分別是多少?
乍一看,這題不難,無非就是移位操作,再進行組合。但是呢?對於用Java的童鞋來說,這裡面有一個坑,稍不注意可能就踩進去了。在說之前,我先把程式碼和答案貼出來吧。
看到這裡,可能有的童鞋比較奇怪,為啥要&0xff,這不相當於沒變化嗎?非也,不信我舉個例子。
答案是-127和129。很奇怪不是嗎?我想的明明都是-127啊!!!
解答這個問題之前,我們先注意一下,b1的型別是int,而不是byte,這是因為byte的任何計算操作之後,都預設轉成int,先明確這個概念。
然後,重頭戲來了,大學計算機組成原理我們都學過原碼,反碼和補碼,概念問題這裡就不說了,也不用想書本上那些定義,學以致用嘛,一張圖說明問題。
是不是很easy?這裡再強調一個問題,就是Java中只有有符號數!Java中只有有符號數!Java中只有有符號數!重要的事情說三遍!
那麼好了,Java中的數值儲存就像這個大圓盤!
我們接著看為什麼輸出129?已知byte經過計算之後會變成int,但是人家int是32位的啊,byte才8位,所以只能補位啦,誒呀,問題來啦,怎麼補位呢?這也是今天想強調的哦!
b是byte型別,其計算機儲存的補碼是10000001(8位)。
轉成int後,Java中的擴充套件方式是補符號位擴充套件,何謂補符號位擴充套件?就是變成了11111111 11111111 11111111 10000001(32位),為啥要這樣變?因為這樣變還是-127,數值大小沒有變!
而我們如果&0xff呢? b&0xff=11111111 11111111 11111111 10000001&11111111=00000000 00000000 00000000 10000001,這個值就是129,這就是補零擴充套件啦!所以129的問題解決啦!
什麼?你問補零擴充套件有什麼用?我們回到魏屌的那道題,兩個byte合成一個short,short可是16位哦,如果我們不&0xff,即寫成
s[1] = (short)((bs[2] << 8) | bs[3]);
輸出結果發現變成了-4。為什麼呢?
還是剛才那個思路啊,bs[2]是-3,即11111101,bs[3]是-4,即11111100,
(bs[2] << 8)就變成了11111111 11111111 11111101 00000000,
((bs[2] << 8) | bs[3])就變成了11111111 11111111 11111101 00000000 | 11111111 11111111 11111111 11111100 = 11111111 11111111 11111111 11111100,
再轉成short,就是11111111 11111100,結果就是-4啦!就醬紫!
所以Java中byte和short互相轉換的程式碼應該是:
// short轉byte short x = -32752;//定義一個short byte high = (byte) (0xFF & (x>>8));//定義第一個byte byte low = (byte) (0xFF & x);//定義第二個byte System.out.println(high);//列印第一個byte值 System.out.println(low);//列印第二個byte值 // byte轉short short z = (short)(((high & 0xFF) << 8) | (0xFF & low)); System.out.println(z);//輸出的結果就是-32752
最後總結一下:
因為Java中只有有符號數,當byte擴充套件到short, int時,即正數都一樣,因為符號位是0,所以無論如何都是補零擴充套件;但負數補零擴充套件和按符號位擴充套件結果完全不同。
補符號數,原數值不變。
補零時,相當於把有符號數看成無符號數,比如-127 = 0x81,看成無符號數就是129, 256 + (- 127)。
對於有符號數,從小擴充套件大時,需要用&0xff這樣方式來確保是按補零擴充套件。
而從大向小處理,符號位自動無效,所以不用處理。