bytebuffer的get()和put()带索引方法支持字节级随机访问,不改变position/limit/mark;索引从0开始且以字节为单位,需满足index+typesize≤limit,并受byteorder影响。

ByteBuffer 的 get() 和 put() 方法支持带索引的随机访问,可直接读写缓冲区中任意位置的变量值,无需移动 position。关键在于:索引从 0 开始、需确保不越界、注意字节序(ByteOrder)对多字节类型的影响。
定位读取指定位置的数值(getXXX(index))
使用带索引的 get 方法(如 getShort(2)、getInt(4))可跳过当前 position,直接从指定字节偏移处读取对应类型的值。该操作不改变 buffer 的 position、limit 或 mark。
- 索引单位是字节,不是元素个数。例如
getInt(8)表示从第 8 个字节(即 offset=8)开始连续读取 4 字节解析为 int - 必须保证
index + typeSize ≤ limit,否则抛出IndexOutOfBoundsException。例如容量为 16 的 buffer 中,getLong(12)合法(12+8=20 > 16?不合法!实际会越界),而getLong(8)才安全(8+8=16 ≤ 16) - 读取结果受 buffer 当前
order()影响。默认为 BIG_ENDIAN;若需 little-endian,先调用buffer.order(ByteOrder.LITTLE_ENDIAN)
定位写入指定位置的数值(putXXX(index, value))
与 get 类似,带索引的 put 方法(如 putChar(6, 'A')、putFloat(10, 3.14f))直接在指定字节位置写入编码后的字节,也不影响 position。
- 写入起始索引同样以字节为单位,且需满足
index + typeSize ≤ limit - 写入内容按当前 ByteOrder 编码。例如
putShort(0, (short)0x1234)在 BIG_ENDIAN 下存为12 34,在 LITTLE_ENDIAN 下存为34 12 - 不会触发 compact/flip 等状态变更,适合“打点式”填充结构化数据(如协议头字段、帧内偏移量)
实战:模拟写入一个含 header 的自定义结构体
假设协议格式为:4 字节 magic(int)、2 字节 version(short)、8 字节 timestamp(long)、4 字节 payloadLen(int)。可用 put 精确填入各字段:
ByteBuffer buf = ByteBuffer.allocate(20); buf.putInt(0, 0x464F4F5A); // magic at offset 0 buf.putShort(4, (short)1); // version at offset 4 buf.putLong(6, System.currentTimeMillis()); // timestamp starts at offset 6 buf.putInt(14, 1024); // payloadLen at offset 14 // 此时 buf.position() 仍为 0,未自动推进
后续可通过 buf.getInt(0)、buf.getShort(4) 等方式校验或修改特定字段,完全绕过顺序读写逻辑。
注意事项与常见陷阱
直接索引操作灵活,但容易因计算错误引发越界或错位。务必注意以下几点:
- 不要混淆“Java 类型大小”和“实际占用字节数”:char 是 2 字节,double 是 8 字节,boolean 不支持直接 put/get(需用 byte 模拟)
- get/put 索引方法不能用于 boolean、String 等非基本类型;字符串需手动转 byte[] 后用
put(int index, byte[] src) - 如果 buffer 是只读的(
asReadOnlyBuffer()),调用任何 put 方法都会抛ReadOnlyBufferException - 多线程并发访问同一 buffer 时,带索引的方法虽不改 position,但仍需外部同步,因底层字节数组共享










