Java中的byte & 0xff到底有什么作用?
如果寫過通信類的代碼,比如socket編程,應(yīng)該對這個問題不陌生。
先說結(jié)論
byte & 0xff 是將byte從(-128 至 127)轉(zhuǎn)化成 int(轉(zhuǎn)化后的數(shù)值范圍: 0 至 255)。
其實就是1個byte有兩種表示方法,我們既可以用-128 - 127這段范圍來表示一個字節(jié),也可以用 0 - 255這個范圍的數(shù)來表示一個字節(jié)。
看一個demo
用Java中的InetAddress類來獲取我當前的ip
public class InetAddressTest { public static void main(String[] args) throws UnknownHostException { InetAddress localHost = InetAddress.getLocalHost(); byte[] address = localHost.getAddress(); for (byte b : address) { System.out.print(b + " "); } } }
輸出結(jié)果
-64 -88 2 119
本機ip
好像不太一樣,我們ip地址只用 0 - 255來表示,不會出現(xiàn)負數(shù)。
所以再換一種寫法,將取出來的字節(jié) & 0xff
public class InetAddressTest { public static void main(String[] args) throws UnknownHostException { InetAddress localHost = InetAddress.getLocalHost(); byte[] address = localHost.getAddress(); for (byte b : address) { System.out.print( ( b & 0xff ) + " "); } } }
結(jié)果
192 168 2 119
Process finished with exit code 0
果然就是我們想要的結(jié)果
為什么需要轉(zhuǎn)換
因為Java中的byte是有符號的,他的范圍只能是 -128 - 127。
我們在使用tcp等協(xié)議的時候,首先要把傳輸?shù)南⑥D(zhuǎn)化成字節(jié)流,然后再傳輸,在編程語言中字節(jié)流通常用十進制的byte數(shù)組來表示。
假如我們就想用 0-255來表示一個字節(jié),不想用負數(shù),該怎么辦呢?
可惜Java中沒有 無符號字節(jié)(unsigned byte), 我們只能用 int 來存儲0-255。
而int的范圍是(-2^31 ~ 2^31-1),只用了256個,剩下的空間都被浪費了,得不償失啊。
所以我們存儲的時候、傳輸?shù)臅r候可以用byte,但是使用的時候就需要做一個轉(zhuǎn)換了,那為什么0xff就可以得到無符號byte呢。
& 0xff的作用
作為一個十六進制數(shù),0xff在Java中是用什么類型存儲的呢?
應(yīng)該顯而易見吧,0xff是整型。
假設(shè)我現(xiàn)在要轉(zhuǎn)化 字節(jié) -1
-1的原碼、反碼、補碼分別如下:
原碼 1 0 0 0 0 0 0 1 反碼 0 1 1 1 1 1 1 0 補碼 0 1 1 1 1 1 1 1
現(xiàn)在和 0xff做運算, ff 就是(1111 11111),而因為他是整型,占4個字節(jié),32為,所以0Xff的前面還有24個0。
用 -1 的補碼進行計算
-1 0 1 1 1 1 1 1 1 0xff 000000000 000000000 000000000 1 1 1 1 1 1 1 1 = 000000000 000000000 000000000 0 1 1 1 1 1 1 1 = 255
其實在Java中,”任何數(shù) & 0Xff等于那個數(shù)本身“ 這句話就顯得不那么正確了
”任意整型 & 0xff = 本身“ 是沒有問題的
但是字節(jié) & 0xff 就被拖到了另一個次元,從byte進化成了int。
關(guān)于byte[ ] & 0xFF的問題
最近在寫有關(guān)SHA256加密解密的問題,發(fā)現(xiàn)有一段代碼是這樣的,處于好奇理解了一下。
private static String byte2Hex(byte[] bytes){ StringBuffer stringBuffer = new StringBuffer(); String temp = null; for (int i=0;i<bytes.length;i++){ temp = Integer.toHexString(bytes[i] & 0xFF); if (temp.length()==1){ //1得到一位的進行補0操作 stringBuffer.append("0"); } stringBuffer.append(temp); } return stringBuffer.toString(); }
Integer類中toHexString方法的參數(shù)是int類型,為什么byte[ ] & 0xFF可以表示int類型呢?
byte[i]是8位二進制,0xFF轉(zhuǎn)化為8位二進制為11111111,& 之后的結(jié)果還是本身啊,這是怎么回事?
我們都知道計算機內(nèi)的存儲都是利用二進制的補碼進行存儲的。
復(fù)習(xí)一下,原碼反碼補碼這三個概念
對于一個字節(jié)的最高位,計算機中是有規(guī)定的,正數(shù)的最高位為0,負數(shù)的最高位為1。
對于正數(shù)(00000001)原碼來說,首位表示符號位,反碼 補碼都是本身
對于負數(shù)(100000001)原碼來說,反碼是對原碼除了符號位之外作取反運算即(111111110),補碼是對反碼作+1運算即(111111111)
下面寫段代碼測試下
public static void main(String[] args) { byte[] a=new byte[10]; a[0]=-127; System.out.println("a[0]:"+a[0]); int b=a[0] & 0xFF; System.out.println("b:"+b); }
得到的結(jié)果為:
a[0]:-127
b:129
現(xiàn)在針對這個結(jié)果進行分析:
byte類型的a[0]的值為-127,在計算機中存儲的補碼為:10000001,這個補碼是8位的,而int類型是32位的,所以a[0]作為int類型來輸出的時候jvm給做了個補位便成了 111111111111111111111111 10000001(-127),雖然補碼轉(zhuǎn)換了,但是這兩個補碼表示的十進制數(shù)字是相同的。
為了保證二進制數(shù)據(jù)的一致性,當byte要轉(zhuǎn)化為int的時候,高的24位必然會補1,這樣,其二進制補碼其實已經(jīng)不一致了,如果二進制被當作byte和int來解讀,其10進制的值必然是不同的,因為符號位位置已經(jīng)發(fā)生了變化,而&0xFF可以將高的24位置為0,低8位保持原樣。
int b = a[0]&0xff; a[0]&0xff=1111111111111111111111111 10000001&11111111=000000000000000000000000 10000001 ,這個值就是129
所以最后顯示的b的值為129
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot如何獲取相對路徑文件夾下靜態(tài)資源的方法
這篇文章主要介紹了springboot如何獲取相對路徑文件夾下靜態(tài)資源的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05Springboot?RestTemplate設(shè)置超時時間的簡單方法
學(xué)習(xí)springboot ,RestTemplate的使用場景非常非常多,比如springcloud中的服務(wù)消費,下面這篇文章主要給大家介紹了關(guān)于Springboot?RestTemplate設(shè)置超時時間的簡單方法,需要的朋友可以參考下2022-01-01Java?spring?boot實現(xiàn)批量刪除功能詳細示例
這篇文章主要給大家介紹了關(guān)于Java?spring?boot實現(xiàn)批量刪除功能的相關(guān)資料,文中通過代碼以及圖文將實現(xiàn)的方法介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-08-08