Java通过每两个字节连接

时间:2018-12-25 18:47:19

标签: java arrays int byte short

我有一个byte[ ]数组。我如何每2个字节连接(为每个人获取16位的短尺寸值)并转换为int

我正在使用for循环进行转换,但是我的字节数组很长,所以for循环使其变慢了。

例如:

字节数组就像:{0x00, 0x01, 0x01, 0x02, 0x03, 0x04}

我要每2个字节连接为:{0x0001, 0x0102, 0x0304}

然后得到一个 int [] 数组,例如:{ 1, 258, 772 },依此类推...

我可以简单地说,通过连接两个字节来获取小尺寸(16位)值,然后将其强制转换为int。

这就是我现在过世的方式,但是很慢:

byte[] buffer; // This is my byte array
int[] intBuffer = new int[buffer.length / 2];

for(int i = 0; i < buffer.length-1; i+=2){
    intBuffer[i/2] = ((buffer[i] << 8) | buffer[i+1]);
}

我可以使用Java库使此过程更快吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

使用ByteBuffer一次转换两个字节。

public static int[] twoBytesToInts(byte[] bytes) {
    ShortBuffer buffer = ByteBuffer.wrap(bytes).asShortBuffer();
    int[] ints = new int[buffer.remaining()];
    for (int i = 0; i < ints.length; i++)
        ints[i] = buffer.get(i) & 0xFFFF;
    return ints;
}

这使用Unsafe一次读取两个字节,以避免移位等。

直接使用不安全来避免创建对象,您可以执行以下操作。

public static Unsafe getUnsafe() {
    try {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        return (Unsafe) theUnsafe.get(null);
    } catch (NoSuchFieldException | IllegalAccessException e) {
        throw new AssertionError(e);
    }
}

public static int[] unsafeTwoBytesToInts(byte[] bytes) {
    Unsafe unsafe = getUnsafe();
    int[] ints = new int[bytes.length / 2];
    for (int i = 0; i < ints.length; i++)
        ints[i] = Short.reverseBytes(
                unsafe.getShort(bytes, i * 2 + Unsafe.ARRAY_BYTE_BASE_OFFSET)) & 0xFFFF;
    return ints;
}

与此运行

public static void main(String... args) {
    byte[] bytes = {0x00, 0x01, 0x01, 0x02, 0x03, 0x04};
    int[] ints = twoBytesToInts(bytes);
    System.out.println(Arrays.toString(ints));
    int[] ints2 = unsafeTwoBytesToInts(bytes);
    System.out.println(Arrays.toString(ints2));
}

打印

[1, 258, 772]
[1, 258, 772]

注意:如果您阅读Short.reverseBytes的代码,则似乎在x86上发生了移位,JIT用固有的机器代码指令替换了此代码,以执行相同的操作。

public static int[] twoBytesToIntsOriginal(byte[] bytes) {
    int[] intBuffer = new int[bytes.length / 2];

    for (int i = 0; i < bytes.length - 1; i += 2) {
        intBuffer[i / 2] = ((bytes[i] & 0xFF) << 8) | (bytes[i + 1] & 0xFF);
    }
    return intBuffer;
}

通过JMH基准运行32字节字节[]并没有太大区别。

Benchmark              Mode  Cnt   Score   Error   Units
Main.original         thrpt    5  45.552 ± 3.580  ops/us
Main.usingByteBuffer  thrpt    5  39.968 ± 9.818  ops/us
Main.usingUnsafe      thrpt    5  60.660 ± 9.234  ops/us

对于大型数组,创建ByteBuffer和ShortBuffer的成本将不再那么重要,但这也指出了另一种加快解决方案的方法,即重用int[]而是返回长度。

public static int unsafeTwoBytesToInts(byte[] bytes, int[] ints) {
    int len = bytes.length / 2;
    for (int i = 0; i < len; i++)
        ints[i] = Short.reverseBytes(
                unsafe.getShort(bytes, i * 2L + Unsafe.ARRAY_BYTE_BASE_OFFSET)) & 0xFFFF;
    return len;
}

的吞吐量

Main.usingUnsafe  thrpt    5  75.268 ± 9.119  ops/us