在Java中将字节数组转换为整数,反之亦然

Chr*_*ris 128 java types endianness

我想将一些数据存储到Java中的字节数组中.基本上只是每个数字最多可以占用2个字节的数字.

我想知道如何将整数转换为2字节长字节数组,反之亦然.我发现了很多解决方案谷歌搜索,但大多数都没有解释代码中发生了什么.有很多变化的东西,我真的不明白,所以我很感激一个基本的解释.

Jef*_*ado 212

使用java.nio命名空间中找到的类,特别是ByteBuffer.它可以为您完成所有工作.

byte[] arr = { 0x00, 0x01 };
ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
short num = wrapped.getShort(); // 1

ByteBuffer dbuf = ByteBuffer.allocate(2);
dbuf.putShort(num);
byte[] bytes = dbuf.array(); // { 0, 1 }
Run Code Online (Sandbox Code Playgroud)

  • 如果字节数组只包含 1 或 2 个整数,是否太昂贵?不确定构建 `ByteBuffer` 的成本。 (4认同)
  • @JaveneCPPMcGowan 此答案中没有直接实例化。如果您指的是工厂方法“wrap”和“allocate”,它们不会返回抽象类“ByteBuffer”的实例。 (2认同)

Jar*_*zki 120

byte[] toByteArray(int value) {
     return  ByteBuffer.allocate(4).putInt(value).array();
}

byte[] toByteArray(int value) {
    return new byte[] { 
        (byte)(value >> 24),
        (byte)(value >> 16),
        (byte)(value >> 8),
        (byte)value };
}

int fromByteArray(byte[] bytes) {
     return ByteBuffer.wrap(bytes).getInt();
}
// packing an array of 4 bytes to an int, big endian, minimal parentheses
// operator precedence: <<, &, | 
// when operators of equal precedence (here bitwise OR) appear in the same expression, they are evaluated from left to right
int fromByteArray(byte[] bytes) {
     return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}

// packing an array of 4 bytes to an int, big endian, clean code
int fromByteArray(byte[] bytes) {
     return ((bytes[0] & 0xFF) << 24) | 
            ((bytes[1] & 0xFF) << 16) | 
            ((bytes[2] & 0xFF) << 8 ) | 
            ((bytes[3] & 0xFF) << 0 );
}
Run Code Online (Sandbox Code Playgroud)

将有符号字节打包到int中时,每个字节都需要被屏蔽掉,因为由于算术提升规则(在JLS,转换和促销中描述),它被符号扩展为32位(而不是零扩展).

Joshua Bloch和Neal Gafter在Java Puzzlers("每个字节中的大喜悦")中描述了一个有趣的谜题.将字节值与int值进行比较时,将字节符号扩展为int,然后将此值与另一个int进行比较

byte[] bytes = (…)
if (bytes[0] == 0xFF) {
   // dead code, bytes[0] is in the range [-128,127] and thus never equal to 255
}
Run Code Online (Sandbox Code Playgroud)

请注意,所有数字类型都使用Java签名,但char是16位无符号整数类型.

  • @LeifEricson我认为`&0xFF'是必要的,因为它告诉JVM将有符号字节转换成只设置了这些位的整数.否则字节-1(0xFF)将变为int -1(0xFFFFFFFF).我可能是错的,即使我不是它也不会让事情变得更清楚. (8认同)
  • &0xFF确实是强制性的.`byte b = 0; b | = 0x88; System.out.println(Integer.toString(b,16)); //输出:-78 System.out.println(Integer.toString(b&0xFF,16)); //输出:88` (4认同)
  • 当从字节数组解析int时,要注意字节数组的大小,如果它大于4个字节,根据`ByteBuffer.getInt()`的文档:`读取此缓冲区当前位置的下四个字节`,只解析前4个字节,这不应该是你想要的. (2认同)

Jam*_*oms 52

您还可以将BigInteger用于可变长度字节.您可以将其转换为long,int或short,以满足您的需求.

new BigInteger(bytes).intValue();
Run Code Online (Sandbox Code Playgroud)

或表示极性:

new BigInteger(1, bytes).intValue();
Run Code Online (Sandbox Code Playgroud)

要获取字节只是:

new BigInteger(bytes).toByteArray()
Run Code Online (Sandbox Code Playgroud)

  • 请注意,从 1.8 开始,它是 `intValueExact`,而不是 `intValue` (2认同)

pre*_*geo 5

一个基本的实现将是这样的:

public class Test {
    public static void main(String[] args) {
        int[] input = new int[] { 0x1234, 0x5678, 0x9abc };
        byte[] output = new byte[input.length * 2];

        for (int i = 0, j = 0; i < input.length; i++, j+=2) {
            output[j] = (byte)(input[i] & 0xff);
            output[j+1] = (byte)((input[i] >> 8) & 0xff);
        }

        for (int i = 0; i < output.length; i++)
            System.out.format("%02x\n",output[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

为了了解事物,您可以阅读以下WP文章:http : //en.wikipedia.org/wiki/Endianness

上面的源代码将输出34 12 78 56 bc 9a。前2个字节(34 12)表示第一个整数,依此类推。上面的源代码以little endian格式编码整数。


小智 5

/** length should be less than 4 (for int) **/
public long byteToInt(byte[] bytes, int length) {
        int val = 0;
        if(length>4) throw new RuntimeException("Too big to fit in int");
        for (int i = 0; i < length; i++) {
            val=val<<8;
            val=val|(bytes[i] & 0xFF);
        }
        return val;
    }
Run Code Online (Sandbox Code Playgroud)