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 .