Буфер (Buffer) состоит из данных и четырех индексов, используемых для доступа к данным и эффективного манипулирования ими. К этим индексам относятся метка (mark), позиция (position), предельное значение (limit) и вместимость (capacity). Есть методы, предназначенные для установки и сброса значений этих индексов, также можно узнать их значение (табл. 16.7).
Методы, вставляющие данные в буфер и считывающие их оттуда, обновляют эти индексы в соответствии с внесенными изменениями. Следующий пример использует очень простой алгоритм (перестановка смежных символов) для смешивания и восстановления символов в буфере CharBuffer:
</spoiler> Хотя получить буфер CharBuffer можно и напрямую, вызвав для символьного массива метод wrap(), здесь сначала выделяется служащий основой байтовый буфер ByteBuffer, а символьный буфер CharBuffer создается как представление байтового. Это подчеркивает, что в конечном счете все манипуляции производятся с байтовым буфером, поскольку именно он взаимодействует с каналом. На входе в метод symmetricScramble() буфер выглядит следующим образом:
Позиция (pos) указывает на первый элемент буфера, вместительность (cap) и предельное значение (lim) — на последний. В методе symmetricScramble() цикл while выполняется до тех пор, пока позиция не станет равной предельному значению. Позиция буфера изменяется при вызове для него «относительных» методов put() или get(). Можно также использовать «абсолютные» версии методов put() и get(), которым передается аргумент-индекс, указывающий, с какого места начнет работу метод put() или метод get(). Эти методы не изменяют значение позиции буфера. Когда управление переходит в цикл while, вызывается метод mark() для установки значения метки (mar). Состояние буфера в этот момент таково:
Два вызова «относительных» методов get() сохраняют значение первых двух символов в переменных с1 и с2. После этих вызовов буфер выглядит так:
Для смешивания символов нам нужно записать символ с2 в позицию 0, a c1 в позицию 1. Для этого можно обратиться за .«абсолютной» версией метода put(), но мы приравняем позицию метке, что и делает метод reset():
Два вызова метода put() записывают с2, а затем c1:
На следующей итерации значение метки приравнивается позиции:
Процесс продолжается до тех пор, пока не будет просмотрен весь буфер. В конце цикла while позиция находится в конце буфера. При выводе буфера на печать распечатываются только символы, находящиеся между позицией и предельным значением. Поэтому, если вы хотите распечатать буфер целиком, придется установить позицию на начало буфера, используя для этого метод rewind(). Вот в каком состоянии находится буфер после вызова метода rewind() (значение метки стало неопределенным):
При следующем вызове symmetricScramble() процесс повторяется, и буфер CharBuffer возвращается к своему изначальному состоянию.