1. 問題由來
本筆記是由byte&0xff引申出來的。在看某一段代碼的時候發現有這么一個邏輯:
該方法的功能是把四個元素的byte數組轉換成ip4地址,從debug的中間過程可以看出來src的第二個元素為負數-100,但它確實是表示ip地址的第二個字節,且src[1] & 0xff之后又變為了正數156,這其中的現象如何解釋?要想知道這里面的原因,首先需要知道原碼、反碼和補碼的概念。
2. 原碼、反碼和補碼
數字是可以二進制來表示的,比如8的二進制表示為00001000,-8的二進制為10001000,其中最高位為符號位。對於正數來說,其二進制原碼,反碼,補碼均相同。而對於負數來說,反碼等於符號位位不變,其余各位取反;補碼等於其反碼加1。
比如問題中的156,其二進制表示為10011100,其反碼和補碼也是10011100。而-100的二進制表示為11100100,其反碼為10011011,補碼為1011100。這時候會發現156的原碼和-100的補碼是一致的。
3. byte & 0xff的細節
我們知道byte是java的一種基本類型,其大小為一個字節,表示的整數范圍是-128~127。而當其最高為不解釋為符號位時,其最大可以表示的數為255。因此例子中字節數組的第二個元素debug時被解釋為-100的原因是,156的二進制表示正好可以解釋為帶符號byte的-100,且我們可以發現byte中存儲的內容其實是補碼。
ok,第一個問題清楚了,-100的補碼與無符號的156的二進制表示一致,且java中的byte存儲的是補碼。那么,為什么src[1] & 0xff之后就變回了正數呢?講道理,0xff可以表示為11111111,我們知道和1與運算之后還是其本身,乍一看,這個運算是沒有意義的。
0xff究竟是怎么一回事呢。可以考慮一下下面這段代碼中c的值會是什么:
int a = 255; int b = 0xff; boolean c = a == b;
c的值為true。其實0xff與255沒有本質的區別,一個是十進制一個是十六進制,都是用來表示一個int型正數。回道上面的問題,src[1] & 0xff也就是src[1]與一個整數相與,那么src[1]首先就要先轉換成一個四字節的整數:
11111111 11111111 11111111 10011100,而0xff為一個整數,其四字節表示為00000000 00000000 00000000 1111111,兩者相與的結果為00000000 00000000 00000000 10011100,也即是解釋為整數156,這樣也就達到了想要獲取byte中實際裝入的無符號156的目的。