日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

字节的游戏

發(fā)布時(shí)間:2024/1/17 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字节的游戏 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

業(yè)務(wù)處理上,有時(shí)會(huì)直接對(duì)字節(jié)進(jìn)行操作。例如實(shí)現(xiàn)私有協(xié)議,對(duì)校驗(yàn)位進(jìn)行檢測(cè),敏感數(shù)據(jù)加密等。博主查了 一下網(wǎng)上的資料,發(fā)現(xiàn)有不少都是錯(cuò)誤的。甚至連《Thinking in Java》的解釋都很令人困惑,以下是從書(shū)中摘錄的原文:

如果對(duì)char、byte或者short類型的數(shù)值驚醒移位處理,那么在移位之前,他們會(huì)被轉(zhuǎn)換為int類型,并且得到的結(jié)果也是一個(gè)int類型。只有數(shù)值右端的低5位才有用。

當(dāng)時(shí)讀到這一句的時(shí)候,我理解了很久,至今沒(méi)有明白“只有數(shù)值右端的低5位才有用”的含義。理解字節(jié)處理的基本方法就是動(dòng)手操作,下面我會(huì)結(jié)合用例進(jìn)行解釋。

首先,我們需要理解幾個(gè)基礎(chǔ)概念。一般來(lái)說(shuō),字節(jié)是我們可以用語(yǔ)言處理的最小對(duì)象,無(wú)論是C/C++還是Java都沒(méi)有直接提供bit類型。1 byte = 8 bit,除去最左側(cè)的符號(hào)位1byte可以描述的范圍是:-128 ~ 127。但是在大多數(shù)的業(yè)務(wù)處理中,我們通常會(huì)采用無(wú)符號(hào)位,即用1byte表示:0 ~ 255。其次,常見(jiàn)的移位操作符有左移(<<) 和右移 (>>),比較容易忽視的是右移操作,如果最左側(cè)的符號(hào)位為1則右移是在高位插入的是——1。因此Java中增加了一種“無(wú)符號(hào)”右位移操作符>>>,通常用不上了解即可。最后,如果我們采用byte[]來(lái)表示一種數(shù)據(jù)類型,數(shù)組下標(biāo)從小到大即內(nèi)存地址的從低位到高位。記住這個(gè)概念非常重要,后面我會(huì)引入大端模式與小端模式。

為了讓大家理解以上概念,下面看兩個(gè)例子:

1. 假設(shè)byte x = 127,對(duì)它執(zhí)行左移1位的操作 x = ?

byte x = 127; x <<= 1; System.out.println(Integer.toHexString(x));

在代碼執(zhí)行之前我們先使用計(jì)算器計(jì)算一下:BIN(1111 1110) HEX(FE),代碼的執(zhí)行結(jié)果為:FFFFFFFE。原因是對(duì)x左移1位超出了byte的表示范圍,Java自動(dòng)在左側(cè)補(bǔ)位,由于最高位是1,因此我們獲得了一個(gè)怪異的結(jié)果。那么有什么辦法得到一個(gè)正確的結(jié)果呢?

byte x = 127; x <<= 1; System.out.println(Integer.toHexString(x & 0xFF));

2. 假設(shè)byte x = 1,對(duì)它執(zhí)行左移32位的操作 x = ?

byte x = 1; System.out.println(x << 32);

答案是1。這個(gè)結(jié)論比較怪異而且確實(shí)是一個(gè)坑,大家只需要記住:對(duì)一個(gè)int值來(lái)說(shuō),左移32位等于它的原始值;對(duì)于一個(gè)long值來(lái)說(shuō),左移64位等于它的原始值。

在理解了這些基本概念以后,我們已經(jīng)做好了進(jìn)入字節(jié)世界的準(zhǔn)備。

我們?nèi)绾斡?個(gè)字節(jié)的大端模式表示一個(gè)整型變量?

對(duì)大端模式的定義為:數(shù)據(jù)的高字節(jié)保存在內(nèi)存的低地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的高地址中。這個(gè)說(shuō)法很繞而且也不利于理解,對(duì)于數(shù)字常量來(lái)說(shuō)0x1234,1即為高位,4即為低位。而對(duì)于byte[4]來(lái)說(shuō),bs[0]即為地址低位,bs[3]即為地址高位。這樣看來(lái)就很清楚了。大端模式符合人們的閱讀模式。

int i = 0x1234; byte[] bs = new byte[4]; bs[3] = (byte) (i & 0xFF); bs[2] = (byte) (i >> 8 & 0xFF); bs[1] = (byte) (i >> 16 & 0xFF); bs[0] = (byte) (i >> 24 & 0xFF);for(byte b : bs) {System.out.println(Integer.toHexString(b)); }

更抽象的算法,大家可以在理解了上面的例子以后自己封裝。

反過(guò)來(lái)我們將以大端模式生成的4個(gè)字節(jié)還原為一個(gè)整型數(shù)?

int x = bs[3] & 0xFF; x |= bs[2] & 0xFF << 8; x |= bs[1] & 0xFF << 16; x |= bs[0] & 0xFF << 24;System.out.println(Integer.toHexString(x));

注意:為了得到正確的結(jié)果,我們?cè)趯?duì)byte進(jìn)行移位前一定要先做位與(&)操作。

接下來(lái)我們需要升級(jí)問(wèn)題,將一個(gè)8個(gè)字節(jié)寬度的符合大端模式的字節(jié)數(shù)組還原為一個(gè)長(zhǎng)整型數(shù)。

long x = bs[7] & 0xFF; x |= (bs[6] & 0xFF) << 8; x |= (bs[5] & 0xFF) << 16; x |= (bs[4] & 0xFF) << 24; x |= (bs[3] & 0xFF) << 32; x |= (bs[2] & 0xFF) << 40; x |= (bs[1] & 0xFF) << 48; x |= (bs[0] & 0xFF) << 56; System.out.println(Long.toHexString(x));

?

似乎我們很容易按照整型的轉(zhuǎn)換方式得到以上算法。不幸的是,這樣做是錯(cuò)誤的。如果這個(gè)byte[]表示的數(shù)字范圍超過(guò)整型數(shù)的上限,我們將無(wú)法獲得正確的長(zhǎng)整型數(shù)。原因是Java默認(rèn)在對(duì)byte進(jìn)行移位操作前會(huì)轉(zhuǎn)換為int類型,還記得上面我們讓大家記住“對(duì)一個(gè)int值來(lái)說(shuō),左移32位等于它的原始值”嗎?正確的做法應(yīng)該是這樣:

long x = bs[7] & 0xFF; x |= ((long)bs[6] & 0xFF) << 8; x |= ((long)bs[5] & 0xFF) << 16; x |= ((long)bs[4] & 0xFF) << 24; x |= ((long)bs[3] & 0xFF) << 32; x |= ((long)bs[2] & 0xFF) << 40; x |= ((long)bs[1] & 0xFF) << 48; x |= ((long)bs[0] & 0xFF) << 56; System.out.println(Long.toHexString(x));

?

至此我們應(yīng)該可以很輕松的解決有關(guān)字節(jié)轉(zhuǎn)換的各種難題了,但是上面的這些算法未免顯得太不優(yōu)美,幸虧Java早就為我們想到了這一點(diǎn)。本著不要重復(fù)造輪子的觀點(diǎn),我提供了一套工具。

/*** 任意字節(jié)寬度轉(zhuǎn)換為標(biāo)準(zhǔn)整型數(shù)*/ public static int bytesToInt(byte[] bytes, int byteNum, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(4);buffer.order(order);buffer.put(bytes, 0, bytes.length);buffer.put(new byte[buffer.limit() - byteNum], 0, buffer.limit() - byteNum);buffer.flip();return buffer.getInt(); }/*** 長(zhǎng)整型數(shù)轉(zhuǎn)換為指定字節(jié)寬度*/ public static byte[] longToBytes(long x, int byteNum, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(8);buffer.order(order);buffer.putLong(0, x);return Arrays.copyOfRange(buffer.array(), 0, byteNum); }/*** 任意字節(jié)寬度轉(zhuǎn)換為長(zhǎng)整型*/ public static long bytesToLong(byte[] bytes, int byteNum, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(8);buffer.order(order);buffer.put(bytes, 0, bytes.length);buffer.put(new byte[buffer.limit() - byteNum], 0, buffer.limit() - byteNum);buffer.flip();return buffer.getLong(); }/*** 長(zhǎng)整型數(shù)轉(zhuǎn)換為標(biāo)準(zhǔn)的8字節(jié)寬度*/ public static byte[] longToBytes(long x, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(8);buffer.order(order);buffer.putLong(0, x);return buffer.array(); }/*** 標(biāo)準(zhǔn)8字節(jié)寬度轉(zhuǎn)換為長(zhǎng)整型數(shù)*/ public static long bytesToLong(byte[] bytes, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(8);buffer.order(order);buffer.put(bytes, 0, bytes.length);buffer.flip();return buffer.getLong(); }/*** 整型數(shù)轉(zhuǎn)換為標(biāo)準(zhǔn)4字節(jié)寬度*/ public static byte[] intToBytes(int x, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(4);buffer.order(order);buffer.putInt(0, x);return buffer.array(); }/*** 標(biāo)準(zhǔn)4字節(jié)寬度轉(zhuǎn)換為整型數(shù)*/ public static int bytesToInt(byte[] bytes, ByteOrder order) {ByteBuffer buffer = ByteBuffer.allocate(4);buffer.order(order);buffer.put(bytes, 0, bytes.length);buffer.flip();return buffer.getInt(); }

轉(zhuǎn)載于:https://www.cnblogs.com/learnhow/p/10800153.html

總結(jié)

以上是生活随笔為你收集整理的字节的游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。