使用按位运算符将 byte 转换为 int

convert byte to int using bit wise opertators

我正在 Java 中记录一些代码。在我问我的问题之前,我会给你们一些背景信息。目标是读取和处理 orsm file 这是一个包含十六进制代码的文件。

流程如下:使用FileChannel将一些字节读入ByteBuffer。缓冲区填满后,将每个字节转换为有符号整数。这是使用按位 & 运算符和带符号的左移运算符 << 完成的,看起来像这样:

return  (0x000000ff & (bb.get() << 0)) |
        (0x0000ff00 & (bb.get() << 8)) |
        (0x00ff0000 & (bb.get() << 16)) |
        (0xff000000 & (bb.get() << 24));

其中bb当然是ByteBuffer。我完全不知道这段代码如何工作以及为什么工作,我用谷歌搜索了一下,发现最接近的是以下 Stack Overflow 问题:Converting java method to C#: converting bytes to integers with bit shift operators。我仍然一无所知,我想知道是否有人可以帮助我找出这段代码?

这从底层字节缓冲区读取四个字节并将它们拼接成一个 int 值,如下所示:

                        11111111 (first byte read)
                22222222         (second byte read)
        33333333                 (third byte read)
44444444                         (fourth byte read)

为此,对所有子结果执行按位或运算,其中每个子结果在上图中准备一行。比如第三行准备为

(0x00ff0000 & (bb.get() << 16))

执行以下操作:

  1. 读取字节:

    xxxxxxxx
    
  2. byte 扩展为 int:

    000000000000000000000000xxxxxxxx        
    
  3. 将位向左移动 16 个槽位:

    00000000xxxxxxxx0000000000000000
    
  4. 最后,将其推入一个 AND 掩码,该掩码仅允许 x 位通过。这是必需的,因为 byte 已签名,因此转换为 int 实际上可能会导致以下结果:

    111111111111111111111111xxxxxxxx
    

如果在 移位之前执行常量与掩码,代码可能会更简单:

(bb.get() & 0xFF) << 16

这实际上是 Java 在这些位操作中的标准习语。


虽然不是您提出的问题的答案,但使用提供的 API 肯定是首选(getInt 方法)。您的字节顺序是小端,所以您只需要设置它:

bb.order(ByteOrder.LITTLE_ENDIAN);

作为参考,这是 JDK 对相同代码的实现:

static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
    return (((b3       ) << 24) |
            ((b2 & 0xff) << 16) |
            ((b1 & 0xff) <<  8) |
            ((b0 & 0xff)      ));
}

基本上,它读取四个字节,每个字节是八位,然后将它们组合成一个32位的整数。它通过将每个连续字节向左额外移动 8 位来实现这一点,因此读取的第一个字节被放置在整数 (0-7) 的最后(最低位)8 位中;下一个字节进入下一个 8 位 (15-8),等等

虽然使用 ByteBuffer 的实际功能来执行此操作会容易得多:

bb.order(ByteOrder.LITTLE_ENDIAN); // Called once on the buffer
int intFromNextFourBytes = bb.getInt(); // Read the same value as your code.