位移位和位掩码 - 示例代码

Bit shifting and bit mask - sample code

我遇到过一些具有位掩码 0xff0xff00 或 16 位二进制形式 00000000 1111111111111111 00000000.[=24= 的代码]

/**
 * Function to check if the given string is in GZIP Format.
 *
 * @param inString String to check.
 * @return True if GZIP Compressed otherwise false.
 */
public static boolean isStringCompressed(String inString)
{
    try
    {
        byte[] bytes = inString.getBytes("ISO-8859-1");
        int gzipHeader = ((int) bytes[0] & 0xff)
            | ((bytes[1] << 8) & 0xff00);
        return GZIPInputStream.GZIP_MAGIC == gzipHeader;
    } catch (Exception e)
    {
        return false;
    }
}

我正在尝试弄清楚在此上下文中(针对字节数组)使用这些位掩码的目的是什么。我看不出这会有什么不同?

在 GZip 压缩字符串的上下文中,因为此方法似乎是为 GZip 幻数编写的,所以十六进制为 356158B1F,二进制为 10001011 00011111

我认为这交换字节是否正确?例如,我的输入字符串是 \u001f\u008b

bytes[0] & 0xff00
 bytes[0] = 1f = 00011111
          & ff = 11111111
                 --------
               = 00011111

bytes[1] << 8
 bytes[1] = 8b = 10001011
          << 8 = 10001011 00000000

((bytes[1] << 8) & 0xff00)
= 10001011 00000000 & 0xff00
= 10001011 00000000 
  11111111 00000000 &
-------------------
  10001011 00000000

所以

00000000 00011111
10001011 00000000 |
-----------------
10001011 00011111 = 8B1F

对我来说,在 bytes[0] & 0xff(bytes[1] << 8) & 0xff00) 两种情况下,& 似乎都没有对原始字节做任何事情。我错过了什么?

显然目的是读取 bytes 的第一个单词并通过适当的掩码和移位将它们存储在 gzipHeader 中。更准确地说,第一部分恰好屏蔽了第一个字节,而第二部分屏蔽了已经移动了 8 位的第二个字节。 | 将两个位掩码组合成 int.

将结果值与定义值 GZIPInputStream.GZIP_MAGIC 进行比较,以确定前两个字节是否是使用 gzip 压缩的数据的定义开头。

byte 是有符号类型。如果将 0xff 作为 byte 转换为 int,则会得到 -1。如果你真的想得到255,转换后屏蔽。

int gzipHeader = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);

类型 byte 是 Java 是 已签名 。如果您将 byte 转换为 int,则它是 sign will be extended& 0xff 用于屏蔽从符号扩展中获得的 1 位,有效地将 byte 视为无符号。

0xff00 类似,除了字节首先向左移动 8 位。

所以,它的作用是:

  • 取第一个字节 bytes[0],将其转换为 int 并屏蔽符号扩展位(将字节视为无符号)
  • 取出第二个字节,将其转换为int,将其左移8位,并屏蔽掉符号扩展位
  • 将这些值与 |
  • 合并

请注意,左移有效地交换了字节。

这是克服big-endian/little-endian问题的技巧。它强制将前两个字节解释为小端字节序,即 [0] 包含 low 字节,[1] 包含 high 字节。