Java Language
ByteBuffer
Поиск…
Вступление
Класс ByteBuffer был введен в java 1.4 для облегчения работы с двоичными данными. Он особенно подходит для использования с данными примитивного типа. Это позволяет создавать, но также и последующую манипуляцию byte[] s на более высоком уровне абстракции
Синтаксис
- byte [] arr = новый байт [1000];
- ByteBuffer buffer = ByteBuffer.wrap (arr);
- ByteBuffer buffer = ByteBuffer.allocate (1024);
- ByteBuffer buffer = ByteBuffer.allocateDirect (1024);
- byte b = buffer.get ();
- байт b = buffer.get (10);
- short s = buffer.getShort (10);
- buffer.put ((byte) 120);
- buffer.putChar ( 'а');
Основное использование - создание ByteBuffer
Существует два способа создания ByteBuffer , где можно снова подразделить.
Если у вас уже есть byte[] , вы можете «обернуть» его в ByteBuffer чтобы упростить обработку:
byte[] reqBuffer = new byte[BUFFER_SIZE];
int readBytes = socketInputStream.read(reqBuffer);
final ByteBuffer reqBufferWrapper = ByteBuffer.wrap(reqBuffer);
Это будет возможность для кода, который обрабатывает сетевые взаимодействия на низком уровне
Если у вас нет уже существующего byte[] , вы можете создать ByteBuffer над массивом, специально выделенным для буфера следующим образом:
final ByteBuffer respBuffer = ByteBuffer.allocate(RESPONSE_BUFFER_SIZE);
putResponseData(respBuffer);
socketOutputStream.write(respBuffer.array());
Если код-путь чрезвычайно критичен по производительности и вам нужен прямой доступ к системной памяти , ByteBuffer может даже выделять прямые буферы с помощью #allocateDirect()
Основное использование - запись данных в буфер
Учитывая ByteBuffer экземпляр можно записывать данные примитивного типа к нему с помощью относительного и абсолютного put . Поразительное различие заключается в том, что помещение данных с использованием относительного метода отслеживает индекс, в который данные вставляются для вас, в то время как абсолютный метод всегда требует указания индекса для put данных.
Оба метода позволяют «цепочки» вызовов. При достаточно большом буфере можно сделать следующее:
buffer.putInt(0xCAFEBABE).putChar('c').putFloat(0.25).putLong(0xDEADBEEFCAFEBABE);
что эквивалентно:
buffer.putInt(0xCAFEBABE);
buffer.putChar('c');
buffer.putFloat(0.25);
buffer.putLong(0xDEADBEEFCAFEBABE);
Обратите внимание, что метод, базирующийся на byte не указан специально. Кроме того , обратите внимание , что это справедливо и для передачи одновременно ByteBuffer и byte[] , чтобы put . Кроме этого, все примитивные типы имеют специализированные put методы.
Дополнительная заметка: индекс, указанный при использовании абсолютного значения put* , всегда учитывается в byte .
Основное использование - использование DirectByteBuffer
DirectByteBuffer - это специальная реализация ByteBuffer , у которой нет byte[] .
Мы можем выделить такой ByteBuffer, вызывая:
ByteBuffer directBuffer = ByteBuffer.allocateDirect(16);
Эта операция будет выделять 16 байт памяти. Содержимое прямых буферов может находиться вне обычной кучи мусора.
Мы можем проверить, является ли ByteBuffer прямым, вызывая:
directBuffer.isDirect(); // true
Основные характеристики DirectByteBuffer том, что JVM будет пытаться изначально работать с выделенной памятью без дополнительной буферизации, поэтому выполняемые на ней операции могут быть быстрее, чем выполняемые на ByteBuffers с лежащими под ним массивами.
Рекомендуется использовать DirectByteBuffer с тяжелыми операциями ввода-вывода, которые полагаются на скорость выполнения, например, в режиме реального времени.
Мы должны знать, что если мы попытаемся использовать метод array() мы получим UnsupportedOperationException . Таким образом, это хорошая практика, чтобы проверить, есть ли у нашего ByteBuffer (байтовый массив), прежде чем мы попытаемся получить к нему доступ:
byte[] arrayOfBytes;
if(buffer.hasArray()) {
arrayOfBytes = buffer.array();
}
Другое использование прямого байтового буфера - это взаимодействие через JNI. Поскольку буфер прямого байта не использует byte[] , а представляет собой фактический блок памяти, можно получить доступ к этой памяти непосредственно через указатель в собственном коде. Это может сэкономить массу проблем и накладных расходов при сортировке между Java и собственным представлением данных.
Интерфейс JNI определяет несколько функций для обработки буферов с прямым байтом: поддержка NIO .