Использование 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
для чтения двух байтов за раз, чтобы избежать сдвигов и т. Д.
Использование 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