buffer.mark() 和 buffer.reset() 仅对 position 指针做快照与恢复,mark() 记录当前 position,reset() 将 position 回设至 mark 值,不改变 limit、capacity 或数据内容,且 clear()/flip()/rewind() 会清除 mark。

Java NIO 中的 Buffer.mark() 和 Buffer.reset() 不是“通用回退工具”,而是对 position 指针做快照与恢复,用法必须紧扣缓冲区状态规则——mark 仅在 position 移动过程中临时锚定一个读写位置,reset 只能回到那个位置,不涉及数据、limit 或业务含义。
mark/reset 的基本行为和前提条件
Buffer 的 mark 是一个可选标记位,默认为 -1(未设置)。只有显式调用 mark() 后,它才被设为当前 position 值;之后无论 get()、put()、flip() 还是 compact() 怎么改 position,只要没调 clear() 或重新分配 buffer,mark 就保持不变。调用 reset() 时,仅把 position 设回 mark 所在位置,limit 和 capacity 完全不受影响。
-
mark()不改变position,只“拍照”当前值 -
reset()不恢复limit,也不清空数据,只重设position -
clear()、flip()、rewind()都会将mark重置为 -1(丢弃标记) -
mark ≤ position ≤ limit ≤ capacity这个约束始终成立
什么时候适合用 mark/reset 来记录“变量处理位置”
所谓“变量处理位置”,本质是你在解析一段字节流(如协议头、JSON 字段、CSV 列)时,某个字段读取完成后,想保留现场以便后续出错时回退重试或跳过。这时可以把“刚读完该字段后的 position”作为 mark。
- 解析固定头 + 可变体协议:读完 4 字节 length 字段后立即
mark(),再按 length 读 body;若 body 解析失败,调reset()回到 length 后,可跳过整包或记录偏移 - 解析多字段文本行:每成功解析一个字段(比如用
get()或slice()),就mark()下一字段起始位置;某字段格式非法时,reset()回到上个mark,尝试容错或定位错误 - 注意:
mark本身不带任何上下文(如字段名、层级、类型),需由业务代码自行维护映射关系,例如用栈存字段标识
常见误用和规避方式
mark/reset 容易因状态混乱失效,关键要守住三条线:
- 不要在
flip()或clear()后还依赖旧mark——它们会清掉标记,必须重新mark() - 避免跨 buffer 使用:每个 buffer 的
mark是独立状态,不能复制或共享 - 别指望
reset()恢复数据内容:底层数组内容始终存在,但position回退后是否能读到原数据,取决于你之前有没有覆盖写入 - 如果需要多次嵌套回溯(比如解析嵌套结构),建议配合栈管理多个
mark,每次reset()后手动重新mark()新位置
对比其他指针操作方法
mark/reset 和 rewind()、flip()、clear() 各有分工:
-
rewind():强制position = 0,适合重复读已写内容,不关心之前在哪停过 -
flip():用于写转读,设limit = position、position = 0,是标准读写切换动作 -
clear():准备新一次写入,设position = 0、limit = capacity,常用于 channel.read() 前 -
mark/reset:唯一支持“非起点回退”的机制,适用于局部试探、字段级回溯等灵活场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











