ByteBuffer.put不能直接写入非byte类型数据,必须用putInt()等专用方法;写入需严格对齐字节序与大小,注意remaining()空间、编码转换及flip()切换读写状态。

ByteBuffer.put 不能直接写入非 byte 类型数据
ByteBuffer.put 系列方法中,只有 put(byte) 是直接写入单个字节的;所有其他类型(int、short、float 等)都必须调用对应类型的专用方法,比如 putInt()、putShort()、putFloat()。误以为 put(123) 能写入 int 是常见错误——那会触发自动装箱为 Byte.valueOf((byte)123),实际只写入低 8 位。
按顺序填充多类型数据必须严格对齐字节序和大小
Java 的 ByteBuffer 默认使用大端序(BIG_ENDIAN),且每种类型有固定字节长度:short 占 2 字节、int 占 4 字节、long 占 8 字节、double 占 8 字节。如果顺序写入 putShort(0x0102) 后接 putInt(0x03040506),缓冲区内容就是连续的 0x01 0x02 0x03 0x04 0x05 0x06(大端),共 6 字节。一旦顺序错乱或未对齐(比如在 3 字节偏移处调用 putInt()),虽不会抛异常,但读取时会解包出错误值。
- 务必在写入前检查
buffer.remaining()是否足够容纳下一个类型 - 避免混用
put(byte[])和putXxx():前者不改变字节序,后者受order()控制 - 若需小端序,显式调用
buffer.order(ByteOrder.LITTLE_ENDIAN),且必须在任何putXxx()之前设置
写入字符串需先转 byte[] 并注意字符编码
ByteBuffer 没有 putString() 直接方法。常见做法是用 "hello".getBytes(StandardCharsets.UTF_8) 得到 byte[],再用 put(byte[]) 写入。但要注意:
- 字符串长度不确定 → 必须提前预留足够空间,或先计算
str.getBytes(StandardCharsets.UTF_8).length - 不同编码结果字节数不同:
"€"在 UTF-8 下占 3 字节,在 ISO-8859-1 下会抛UnmappableCharacterException - 若协议要求带长度前缀(如 2 字节表示后续字符串字节数),需手动
putShort((short)len)再put(bytes)
position 自动推进,但 flip() / clear() 容易被忽略
每次 putXxx() 都会使 position 增加对应字节数。写完所有数据后,若要读取,必须调用 flip() —— 它把 limit 设为当前 position,再把 position 归零。否则 getXXX() 会从末尾开始读,返回 0 或乱码。
示例片段:
ByteBuffer buf = ByteBuffer.allocate(16); buf.putInt(0x12345678); // position=4 buf.putShort((short)0xABCD); // position=6 buf.put((byte)0xEF); // position=7 buf.flip(); // limit=7, position=0 → 可安全 get*
反复复用缓冲区时,别用 clear()(重置为可写状态)代替 flip(),否则刚写的数据会被后续 put 覆盖。
字节序、剩余空间、编码转换、position 生命周期——这四个点任意一个没控住,填充出来的二进制流就不可靠。

















