Java?int類型如何獲取高低位
int類型如何獲取高低位
去年筆者和一個硬件廠商調(diào)試打印機(jī)的時候遇到這個一個問題,廠商需要打印報文中傳輸報文的長度標(biāo)志,按大端序,將長度的高位和低位放到兩個字節(jié)里,筆者由于基礎(chǔ)知識不牢固,在這個問題上浪費了較長時間,今年開始寫博客了,就記錄一下這個問題。筆者使用了int來記錄長度,其實應(yīng)該用兩個字節(jié)的short來記錄,這樣更簡單。
大小端序
要想拿int的高低位字節(jié),首先要理解大小端序。這里以int舉例,int有四個字節(jié)A,B,C,D。那么內(nèi)存里存儲int類型占用了四個字節(jié)的位置,這四個字節(jié)在內(nèi)存中肯定占用了連續(xù)遞增的四個地址,大小端序指得就是這四個字節(jié)在這四個地址中是順序排列的還是逆序排列的。如果是順序排列的,那么我們叫大端序,如果是逆序排列的,就叫小端序。
再拿網(wǎng)絡(luò)傳輸這個int值來舉例,甲向乙傳輸數(shù)據(jù),乙拿到甲傳的字節(jié)數(shù)組以后要知道怎么拼接這四個字節(jié),如果甲是按順序傳輸這四個字節(jié),而乙按逆序拼接四個字節(jié),那么雙方得到的int值肯定是不一樣的。那么怎么解決這個問題呢?方法就是雙方協(xié)定一個順序,比如按大端序傳輸,甲將四個字節(jié)按大端序傳輸給乙,乙再按大端序拼接字節(jié),這樣雙方得到的int值就是一樣的了。
總結(jié)一下就是,大端序,高位字節(jié)在前,低位字節(jié)在后。小端序,高位字節(jié)在后,低位字節(jié)在前。一般交互都是默認(rèn)大端序。
獲取int的高低位字節(jié)數(shù)組
這里給出了大小端序的int和字節(jié)數(shù)組互轉(zhuǎn)函數(shù)
/** * 小端序 字節(jié)數(shù)組轉(zhuǎn)int * * @param bytes * @return */ public static int littleEndian(byte[] bytes) { return (bytes[0]&0XFF) | ((bytes[1]&0XFF) << 8) | ((bytes[2]&0XFF) << 16) | ((bytes[3]&0XFF) << 24); } /** * 大端序 字節(jié)數(shù)組轉(zhuǎn)int * * @param bytes * @return */ public static int bigEndian(byte[] bytes) { //System.out.println(String.format("%32s", Integer.toBinaryString(bytes[3]&0XFF)).replaceAll("\\s", "0")); //System.out.println(String.format("%32s", Integer.toBinaryString(((bytes[2]&0XFF) << 8)).replaceAll("\\s", "0"))); //System.out.println(String.format("%32s", Integer.toBinaryString(((bytes[1]&0XFF) << 16)).replaceAll("\\s", "0"))); //System.out.println(String.format("%32s", Integer.toBinaryString(((bytes[0]&0XFF) << 24)).replaceAll("\\s", "0"))); return (bytes[3]&0XFF) | ((bytes[2]&0XFF) << 8) | ((bytes[1]&0XFF) << 16) | ((bytes[0]&0XFF) << 24); } /** * 大端序 int轉(zhuǎn)字節(jié)數(shù)組 * * @param i * @return */ public static byte[] bigEndian(int i) { int byte1 = i & 0XFF; int byte2 = (i & 0XFFFF) >>> 8; int byte3 = (i & 0XFFFFFF) >>> 16; int byte4 = (i & 0XFFFFFFFF) >>> 24; return new byte[]{(byte) byte4, (byte) byte3, (byte) byte2, (byte) byte1}; } /** * 小端序 int轉(zhuǎn)字節(jié)數(shù)組 * * @param i * @return */ public static byte[] littleEndian(int i) { int byte1 = i & 0XFF; int byte2 = (i & 0XFF << 8) >> 8; int byte3 = (i & 0XFF << 16) >> 16; int byte4 = (i & 0XFF << 24) >> 24; return new byte[]{(byte) byte1, (byte) byte2, (byte) byte3, (byte) byte4}; } public static void main(String[] args) { int a = new Random().nextInt(); String s = String.format("%32s", Integer.toBinaryString(a)).replaceAll("\\s", "0"); System.out.println("原數(shù)據(jù): " + s.substring(0, 8) + " " + s.substring(8, 16) + " " + s.substring(16, 24) + " " + s.substring(24, 32) + " "); byte[] bytes = bigEndian(a); System.out.printf("大端序-int轉(zhuǎn)字節(jié)數(shù)組:"); for (int i = 0; i < bytes.length; i++) { System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i] & 0XFF)).replaceAll("\\s", "0") + " "); } System.out.println(); System.out.println("大端序-字節(jié)數(shù)組轉(zhuǎn)int驗證:" + (bigEndian(bytes) == a)); byte[] bytes2 = littleEndian(a); System.out.printf("小端序-int轉(zhuǎn)字節(jié)數(shù)組:"); for (int i = 0; i < bytes2.length; i++) { System.out.print(String.format("%8s", Integer.toBinaryString(bytes2[i] & 0XFF)).replaceAll("\\s", "0") + " "); } System.out.println(); System.out.println("小端序-字節(jié)數(shù)組轉(zhuǎn)int驗證:" + (littleEndian(bytes2) == a)); } } 原數(shù)據(jù): 10010100 11111001 01101110 00100011 大端序-int轉(zhuǎn)字節(jié)數(shù)組:10010100 11111001 01101110 00100011 大端序-字節(jié)數(shù)組轉(zhuǎn)int驗證:true 小端序-int轉(zhuǎn)字節(jié)數(shù)組:00100011 01101110 11111001 10010100 小端序-字節(jié)數(shù)組轉(zhuǎn)int驗證:true
高低位和byte轉(zhuǎn)int
最近研究I/O流,發(fā)現(xiàn)read()方法返回的是int類型,原來是將一個byte讀入到一個int,有效的數(shù)據(jù)只占據(jù)int型變量的最低8位。在正常情況下這個int型的變量永遠(yuǎn)都不可能是負(fù)數(shù)。
什么是高低位?
一個Byte是8位(bit),其中的“8位”指的是8位2進(jìn)制數(shù)。byte范圍是-128--127,如果輸入超過這個數(shù)值,會編譯錯誤。
如8位二進(jìn)制數(shù):11001010;1100就是高4位,后面的1010就是低4位。
什么是低8位?
一個int類型的變量能存放4Byte,也就是能存放32位二進(jìn)制數(shù),而一個32位二進(jìn)制數(shù)中權(quán)值最大的24位就是高24位,那么剩下的就是低8位。
如何將byte轉(zhuǎn)換為int?
需要將前24位去除,也就是轉(zhuǎn)換為0。Java對byte總是做有符號處理;
所以可以通過將byte和0xff進(jìn)行二進(jìn)制“&“得到它的無符值。
例如:
byte的二進(jìn)制為:11001010;
0xff的二進(jìn)制為:11111111;
1111111111111111111111111 11001010 & 11111111 = 000000000000000000000000 11001010
上面的例子為什么會添加這么多“1”?
當(dāng)系統(tǒng)檢測到byte可能會轉(zhuǎn)化成int或者說byte與int類型進(jìn)行運(yùn)算的時候,就會將byte的內(nèi)存空間高位補(bǔ)1(也就是按符號位補(bǔ)位)擴(kuò)充到32位
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot中的CompletableFuture類詳解
這篇文章主要介紹了SpringBoot中的CompletableFuture類詳解,在?Java8中,引入了CompletableFuture類,它提供了一種簡單而強(qiáng)大的方式來執(zhí)行異步任務(wù),今天我們就來詳細(xì)解讀一下這個類,需要的朋友可以參考下2023-07-07SpringBoot啟動類@SpringBootApplication注解背后的秘密
這篇文章主要介紹了SpringBoot啟動類@SpringBootApplication注解背后的秘密,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12Spring?Boot應(yīng)用程序中如何使用Keycloak詳解
這篇文章主要為大家介紹了Spring?Boot應(yīng)用程序中如何使用Keycloak詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05SpringBoot超詳細(xì)講解集成Flink的部署與打包方法
昨天折騰了下SpringBoot與Flink集成,實際上集成特簡單,主要是部署打包的問題折騰了不少時間。想打出的包直接可以java -jar運(yùn)行,同時也可以flink run運(yùn)行,或者在flink的dashboard上上傳點擊啟動。結(jié)果是不行,但是使用不同的插件打包還是可以的2022-05-05