bytebuffer状态切换取决于position和limit:写完需flip(limit=position, position=0)以读取;读完需clear(position=0, limit=capacity)以复用;部分读取后需compact(移动未读数据至开头,position=剩余长度,limit=capacity)以追加写入。

处理 ByteBuffer 的 flip 与 clear 状态切换,核心是看缓冲区当前处于什么数据阶段,以及你下一步要做什么——不是记方法名,而是盯住 position 和 limit 这两个指针的实际值。
写完数据、准备完整读取:必须调用 flip()
当你用 put() 写入数据,或 channel.read(buffer) 接收完一批字节后,position 已移到写入末尾,limit 仍等于 capacity。此时 buffer 逻辑上是“写满但未锁定范围”,直接 get() 会越界或读到未初始化内容。
- flip() 把 limit 设为当前 position,把 position 归零,mark 清除
- 结果是:读取范围变成 [0, limit),正好覆盖所有已写入的有效字节
- 例如:capacity=1024,写入 32 字节后 position=32,flip() 后 limit=32、position=0,后续 get() 可安全读出全部 32 字节
- flip 后不能再 put(),否则会覆盖未读数据或抛异常
数据已全部读完、准备接收新一批:调用 clear()
当 buffer.hasRemaining() 返回 false(即 position == limit),说明上一轮数据已消费完毕。这时若要复用 buffer 接收下一次 read(),就必须恢复“可写起始状态”。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- clear() 将 position 设为 0,limit 设为 capacity,mark 清除
- 底层字节数组内容不擦除,只是指针重置;下次 put() 或 channel.read(buffer) 会自然覆盖旧数据
- 这是最常用的循环模式:read → flip → get → clear → read…
- 漏掉 clear(),下一次 channel.read(buffer) 可能因 position > 0 导致实际可用写入空间变小,甚至写不进数据
只读了一部分、还要继续写入新数据:改用 compact()
flip 后只读了前几个字节,position 停在中间(比如 limit=100,position=20),剩余 80 字节还没处理,但此时通道又有新数据要写进来——不能 clear(会丢未读数据),也不能再 flip(会重复读)。
- compact() 把 position 到 limit 之间的未读数据复制到缓冲区开头,然后将 position 设为已复制长度(即 80),limit 设为 capacity
- 相当于“腾出前面空间,保留尾巴数据”,为追加写入做准备
- 注意:compact 是唯一真正移动内存数据的操作,其他方法只调指针
不复杂但容易忽略:flip 和 clear 都不碰底层数组,只改 position/limit;它们不是“清空数据”,而是“重新定义边界”。只要每次操作前想清楚——我刚做完什么?接下来要干什么?——状态切换就自然成立。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










