flip()封存写入成果专为读取准备,仅设limit=position、position=0,保留全部已写字节;clear()放弃当前内容重置为可写态,设position=0、limit=capacity,旧字节仍残留但逻辑上失效。

flip() 和 clear() 都会重置 position,但目的、影响范围和底层数据处理逻辑完全不同。关键不在“是否清空”,而在“是否保留已写入的有效字节”以及“为哪种后续操作做准备”。
flip():封存写入成果,专为读取准备
它只做两件事:
— 将 limit 设为当前 position 值(即刚写完的位置)
— 将 position 归零
底层数组一字未动,所有已写入的字节完整保留。此时 buffer 进入“可安全读取”状态:get() 从索引 0 开始,直到 position 达到新的 limit,正好读完全部有效内容。
典型场景:
— channel.read(buffer) 完成后,必须 flip() 才能解析数据
— put 若干字节后,需 get 出来校验或编码,也必须 flip()
误用风险:
— 写完不 flip() 就 get() → 读到 0 或抛 BufferUnderflowException(position 在末尾,limit 还是 capacity)
— 重复 flip() → limit 变成 0,后续读不到任何数据
clear():放弃当前内容,重置为全新写入态
它执行:
— position = 0
— limit = capacity
底层数组仍不变,但逻辑上“丢弃所有已有数据”。因为 limit 拉回到最大容量,下一次 put() 可以从头覆盖写入,旧字节被新数据逐步替代——不是清空内存,而是放弃对它的引用。
典型场景:
— 读完一整包数据后,准备接收下一包,调 clear()
— 解码失败需重试,且不再需要上一轮残留数据时
注意:
— clear() 后若直接 get(),可能读到上一轮残留的脏字节(因 limit = capacity,而那些字节并未被真正擦除)
— 它不是“清内存”,只是重置指针;真正的字节擦除需手动 fill(0) 或依赖 GC 回收整个 buffer
底层字节残留的本质区别
两者都不调用 Arrays.fill() 或类似操作,底层数组内容始终存在,直到 buffer 被 GC 回收或被新数据覆盖。
— flip() 后:旧字节被“逻辑锁定”在 [0, limit) 区间,后续 get() 只读这里,安全可控
— clear() 后:旧字节仍在 [0, capacity) 中,但因 limit = capacity,put() 可能只覆盖前 N 字节,剩余部分仍残留旧数据,形成潜在脏读风险
所以,“残留”本身不是问题,问题在于指针如何界定“有效区间”。flip() 明确划出有效边界;clear() 则默认整个空间都可写,把界定责任交还给开发者。











