buffer.compact()的作用是将未读完的剩余数据移到缓冲区开头并重置写入位置,为后续写入腾出空间;它保留未读数据、仅移动[position, limit)区间内容至起始位置,设position为移动长度、limit为capacity,不改变capacity且不清空数据。

Buffer.compact() 的作用是在未读完数据时,把尚未读取的剩余内容移到缓冲区开头,并重置写入位置,为后续写入腾出空间。它不是清空缓冲区,也不是重置全部指针,而是“整理残留”,让读写指针协同工作。
compact前后的指针状态变化
假设一个容量为10的ByteBuffer,已写入7个字节(limit=7, position=7),然后读取了4个字节(position=4),此时:
- capacity = 10
- limit = 7(仍等于上次写入的上限)
- position = 4(当前读取位置)
- remaining() = limit − position = 3(还有3字节没读)
调用 compact() 后:
- 把 position 到 limit 区间的数据(即 [4,7) 的3个字节)复制到缓冲区起始位置 [0,3)
- position 被设为 3(指向已复制数据的末尾,即下一个可写位置)
- limit 被设为 capacity(即10),表示现在最多还能写入 10−3=7 个字节
- capacity 不变
为什么不能用 clear() 替代 compact()
clear() 会直接重置 position=0、limit=capacity,丢弃所有未读数据。而 compact() 保留未读内容,只是把它“前移”。如果还有数据没消费完就准备继续写入(比如网络收包粘包场景),clear() 会导致数据丢失,compact() 才是安全选择。
典型使用场景:循环读写中的粘包处理
在基于Channel的非阻塞IO中,一次 read() 可能只读到半个消息,下一次 read() 又追加后半部分。这时:
- 第一次读入 5 字节(position=5, limit=5),解析发现消息不完整
- 第二次 read() 尝试再读,但 buffer 已满(position==limit),无法写入
- 调用 compact() 把未解析的 5 字节挪到开头,position 变为 5,limit 变为 capacity,腾出后半段空间
- 第二次 read() 成功写入新数据,拼成完整消息
注意点:compact() 不改变 capacity,也不清空数据
compact() 只移动数据、调整 position 和 limit,底层数组内容不变。被移动的数据仍在原处(只是被覆盖或忽略),不会自动清零。如果对安全性要求高(如含敏感信息),需手动覆盖旧数据区域。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











