为什么在Java中左移以更改符号值

AQU*_*AQU 3 java byte-shifting

我正在使用Java。我想知道为什么Java会产生此输出。我在这里分享代码。

public class vvn {

    public static void main(String[] args)
    {
        byte [] arr = new byte[4];
        arr[0] = (byte)157;
        arr[1] = 1;
        arr[2] = 0;
        arr[3] = 0;
        System.out.format("read 0x%x 0x%x 0x%x 0x%x \n",arr[3],arr[2],arr[1],arr[0]);
        int v = (arr[0] | (arr[1] << 8) | (arr[2] << 16) | (arr[3] << 24));
        System.out.format("read 0x%x\n",v);

    }

}
Run Code Online (Sandbox Code Playgroud)

我得到的输出为

read 0x0 0x0 0x1 0x9d 
read 0xffffff9d
Run Code Online (Sandbox Code Playgroud)

我预计输出应为0x0000019d

pro*_*ook 5

您正在从字节(有符号的8位)转换为整数(有符号的32位)。最高有效位(最左边的一位)保持符号(请参见2的补码)。

15710011101二进制文件。由于您将此值分配给有符号字节(java没有无符号字节),因此实际上这是一个负数-99

现在,当您从字节转换为整数时,将保留该值。在负数的情况下,这意味着将所有位设置为左侧以保留有符号性。就您而言,10011101变为11111111 11111111 11111111 10011101

无论如何,在Java中使用无符号字节是一场噩梦。基本上,您需要使用0xff屏蔽所有内容(以切断“左侧的对象”),如下所示:

int v = ((arr[0] & 0xff) |
    ((arr[1] & 0xff) << 8) |
    ((arr[2] & 0xff) << 16) |
    ((arr[3] & 0xff) << 24));
Run Code Online (Sandbox Code Playgroud)

美丽,不是吗?

更新1:另外,您可能对Guava的UnsignedBytes感兴趣...

更新2: Java 8字节具有toUnsignedInt()和toUnsignedLong()方法。这样,您的计算将变为:

int v = (Byte.toUnsignedInt(arr[0]) |
    (Byte.toUnsignedInt(arr[1]) << 8) |
    (Byte.toUnsignedInt(arr[2]) << 16) |
    (Byte.toUnsignedInt(arr[3]) << 24));
Run Code Online (Sandbox Code Playgroud)