flip()将写转读:limit=position, position=0;clear()重置为可写:position=0, limit=capacity;compact()保留未读数据并压缩至开头,便于追加写。

在 Java NIO 中,ByteBuffer 的 flip()、clear() 和 compact() 是控制缓冲区读写状态的核心方法,它们不改变数据本身,只调整 position、limit 和 mark 这几个关键指针。理解它们的用途和触发时机,是避免“读不到数据”或“写覆盖”的关键。
flip():从写模式切换到读模式
当你往缓冲区写入数据后(比如调用 put()),position 会不断前移,最终停在写入末尾;此时 limit 还是容量上限,不能直接开始读——因为读操作只会从 position 到 limit 之间取数据,而当前 position 可能已超过实际有效数据范围。
flip() 的作用就是把当前 position 设为新的 limit(即标记“有效数据结束位置”),再把 position 重置为 0,让后续 get() 能从头开始读取已写入的数据。
- 典型场景:写完数据后准备调用
channel.read(buffer)或buffer.get() - 等价于:
limit = position; position = 0; mark = -1; - 注意:多次
flip()不会报错但逻辑错误——比如第二次 flip 会让 limit 变成 0,导致读不到任何内容
clear():重置为初始写状态
当一次读写流程完成(比如数据已从 buffer 写入 channel 或已全部读出),你想复用这个 buffer 继续写新数据,就该调用 clear()。
它把 position 设为 0,limit 设为 capacity,并清除 mark。注意:它不会清空底层数组里的字节,只是重置指针——所以旧数据还在,但后续 put() 会从头覆盖。
- 适用场景:一轮 I/O 完成后,准备接收下一批数据(如服务器循环处理客户端请求)
- 和
rewind()不同:rewind()只重置 position=0,limit 不变;clear()同时恢复 limit=capacity - 如果 buffer 中还有未读完的数据,调用 clear 会导致丢失——务必确认数据已处理完毕
compact():保留未读数据,为追加写腾空间
这是最易被误解的方法。当你从 buffer 中只读了一部分数据(比如 position 停在中间),剩余未读数据仍在 buffer 前部,而后面的空间空着。此时若想继续写新数据,又不想丢掉前面未读完的内容,compact() 就派上用场。
它会把从 position 到 limit 之间的未读数据复制到 buffer 起始处,然后将 position 设为已复制数据长度,limit 设为 capacity,mark 清除。相当于“压缩”残留数据到开头,腾出尾部空间继续写。
- 典型场景:使用
get()手动解析协议(如 HTTP header 未读完),需要保留剩余字节并接收后续网络数据 - 注意:compact 是一个复制操作,有性能开销;如果是直接用
channel.read(buffer),通常不需要手动 compact,因为 read 会自动处理 position/limit - 调用后 buffer 处于“可写”状态,但已有部分数据——适合追加写,而非全新写入
这三个方法本质是状态机切换工具,不是数据操作指令。用错顺序(比如 write → clear → get)或混淆语义(把 compact 当作清空)是常见 bug 来源。关键是始终心里清楚:当前 buffer 处在什么阶段?下一步要读还是写?已有数据是否还需保留?
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











