Почему ByteBuffer не сохраняет индексы для putDouble и getDouble?

Мне трудно понять семантику ByteBuffer в следующем сценарии:

int sizeOfDouble = 8;
int numberOfDoubles = 4;
ByteBuffer testBuf = ByteBuffer.allocateDirect(sizeOfDouble*numberOfDoubles);

testBuf.putDouble(0, 1.0);
testBuf.putDouble(1, 2.0);
testBuf.putDouble(2, 3.0);
testBuf.putDouble(3, 4.0);

for (int i = 0; i < numberOfDoubles; ++i) {
    System.out.println("testBuf[" + i + "]: " + testBuf.getDouble(i));
}

Я ожидал увидеть ценности, которые я только что положил в ByteBuffer быть напечатанным на экран. Вместо этого я получаю этот вывод:

testBuf[0]: 4.959404759574682E-4
testBuf[1]: 32.50048828125
testBuf[2]: 32.125
testBuf[3]: 4.0

Значение в третьем индексе, кажется, соответствует тому, что я ожидаю: 4.0. Но почему значения и индексы 0, 1 и 2 не совпадают со значениями, которые я вставил (1.0, 2.0 и 3.0 соответственно)?

Я подозреваю, что неправильно понимаю ByteBuffer работает, но я не смог найти его в Javadoc.

3 ответа

Это потому, что ваш код обрабатывает индекс как индекс в массиве doubles. Начальная запись завершается успешно; затем второй записывает свои байты, кроме первого; третья запись снова перезаписывает байты и так далее. Результаты последней записи не перезаписываются, поэтому 4.0 выходит нетронутым.

Первый аргумент представляет индекс в массив байтов внутри буфера, поэтому вам нужно умножить его на sizeOfDouble:

testBuf.putDouble(0*sizeOfDouble, 1.0);
testBuf.putDouble(1*sizeOfDouble, 2.0);
testBuf.putDouble(2*sizeOfDouble, 3.0);
testBuf.putDouble(3*sizeOfDouble, 4.0);

for (int i = 0; i < numberOfDoubles; ++i) {
    System.out.println("testBuf[" + i + "]: " + testBuf.getDouble(sizeOfDouble*i));
}

Demo.

Первый аргумент putDouble() это индекс байта, а не индекс двойного. Таким образом, двойники, которые вы ставите, перекрываются; четвертый написан последним, поэтому он сохранен, но предыдущие испорчены.

Чтобы получить то, что вы хотите, вам нужно умножить индекс на Double.BYTES и когда пишешь и читаешь их.

Следующее работает как ожидалось:

int numberOfDoubles = 4;
ByteBuffer testBuf = ByteBuffer.allocateDirect(Double.BYTES*numberOfDoubles);

testBuf.putDouble(0, 1.0);
testBuf.putDouble(Double.BYTES, 2.0);
testBuf.putDouble(Double.BYTES * 2, 3.0);
testBuf.putDouble(Double.BYTES * 3, 4.0);

for (int i = 0; i < numberOfDoubles; ++i) {
    System.out.println("testBuf[" + i + "]: " + testBuf.getDouble(i * Double.BYTES));
}

Поскольку вы работаете только с double значения, вы могли бы использовать DoubleBufferвместо:

int numberOfDoubles = 4;
DoubleBuffer testBuf = DoubleBuffer.allocate(numberOfDoubles);

testBuf.put(0, 1.0);
testBuf.put(1, 2.0);
testBuf.put(2, 3.0);
testBuf.put(3, 4.0);

for (int i = 0; i < numberOfDoubles; ++i) {
    System.out.println("testBuf[" + i + "]: " + testBuf.get(i));
}

Или вы могли бы обернуть ByteBuffer с DoubleBuffer:

int sizeOfDouble = Double.BYTES;
int numberOfDoubles = 4;
ByteBuffer testBuf = ByteBuffer.allocateDirect(sizeOfDouble*numberOfDoubles);
DoubleBuffer dblBuf = testBuf.asDoubleBuffer();

dblBuf.put(0, 1.0);
dblBuf.put(1, 2.0);
dblBuf.put(2, 3.0);
dblBuf.put(3, 4.0);

for (int i = 0; i < numberOfDoubles; ++i) {
    System.out.println("dblBuf[" + i + "]: " + dblBuf.get(i));
}
for (int i = 0; i < testBuf.limit(); ++i) {
    System.out.println("testBuf[" + i + "]: " + testBuf.get(i));
}

Выход

dblBuf[0]: 1.0
dblBuf[1]: 2.0
dblBuf[2]: 3.0
dblBuf[3]: 4.0
testBuf[0]: 63
testBuf[1]: -16
testBuf[2]: 0
testBuf[3]: 0
testBuf[4]: 0
testBuf[5]: 0
testBuf[6]: 0
testBuf[7]: 0
testBuf[8]: 64
testBuf[9]: 0
testBuf[10]: 0
testBuf[11]: 0
testBuf[12]: 0
testBuf[13]: 0
testBuf[14]: 0
testBuf[15]: 0
testBuf[16]: 64
testBuf[17]: 8
testBuf[18]: 0
testBuf[19]: 0
testBuf[20]: 0
testBuf[21]: 0
testBuf[22]: 0
testBuf[23]: 0
testBuf[24]: 64
testBuf[25]: 16
testBuf[26]: 0
testBuf[27]: 0
testBuf[28]: 0
testBuf[29]: 0
testBuf[30]: 0
testBuf[31]: 0
Другие вопросы по тегам