出處:https://priesttomb.github.io/%E6%8A%80%E6%9C%AF/2021/01/30/using-byte-array-to-store-high-precision-number/
一個小需求最近剛在專案中接觸到一個類似業務流水號(訂單號)的生成唯一性編號的需求,這個東西之前倒是沒接觸過,在很久以前遇到的最多也就拿資料庫生成自增序列完事,而流水號一般需要其中的資料有意義,並可反推等。
找到程式碼中生成流水號的工具類準備學習參考一番,看到了一些類似如下的程式碼:
byte[] byteArray = new byte[4];byteArray[0] = (byte)(intNum >>> 24);byteArray[1] = (byte)(intNum >>> 16);byteArray[2] = (byte)(intNum >>> 8);byteArray[3] = (byte)(intNum);return byteArray;
由於對 2 進位制、位運算一直是學習遠大於使用,所以一時愣住沒反應過來這裡是做的什麼操作,只是知道在一個 byte 陣列中各拿出幾位來分別儲存一些業務欄位就是生成流水號的關鍵。
在學習研究了一番後,恍然大悟,原來高精度數值用 byte 陣列來儲存是這樣實現的(啊,後知後覺)。
下文均以一個正數轉 byte 陣列舉例。如何用 byte 陣列儲存高精度數值高精度型別直接強轉低精度時,會以低精度的位數為主,忽略高精度資料的其餘高位,所以只用一個 byte 是不夠的。
以一個 int 型別的數值為例,一個 int 有 4 位元組,這就要用一個長度為 4 的 byte 陣列來儲存。
將 int 中每 8 bit 都轉成一個 byte,再形成陣列,就能得到一個儲存著 int 的 byte 陣列。
使用 >>> 運算子,就能快速得到 int 數值中的每個 8 bit,而要把這 4 個 byte “拼”回 int 型數值時,又需要注意其中負數的問題(參考補碼的說明 《關於2的補碼》 )。
如果直接使用左移+與運算,會是這樣:
結果當然是錯的,要把負數“轉正”,用 & 0xff 把高位補 0 ,程式碼如下:
public static int byteToInt(byte[] byteArray) { int intNum = (byteArray[0] & 0xff) << 24 | (byteArray[1] & 0xff) << 16 | (byteArray[2] & 0xff) << 8 | (byteArray[3] & 0xff); return intNum;}
小端序與大端序在需求中,看到了大端序和小端序這個字眼,感覺上一次看到(也可能沒看到)這兩個詞可能是在大學時期的課堂上,於是再查了一下,權當鞏固了。
剛才的示例中,把 int 資料的最高位(即左移 24 位得到的那 1 個位元組)存到了 byte 陣列最小的第 0 位,而最低位(即末尾的那 1 個位元組)存到了 byte 陣列最大的第 3 位,這種順序就是位元組的大端序。
大端序某種程度上來說,更符合大多數人類的感官,比如列出一個數組來,下標小的在左邊,下標大的在右邊,而剛好從左到右存的是資料的高位到低位,一目瞭然。
小端序與大端序相反,把資料的高位位元組放在陣列的最後,而低位位元組放到第 0 位,比如上面的 int 值 339930228 用小端序儲存,則是 [116, -20, 66, 20] 。
關於位元組順序,也只是瞭解這麼一個概念,更詳細的可以參考 《理解位元組序》 、 《位元組順序》 。
出處:https://priesttomb.github.io/%E6%8A%80%E6%9C%AF/2021/01/30/using-byte-array-to-store-high-precision-number/