bytebuffer 的 compact() 方法用于在复用缓冲区时,将未读数据(已标记位置到当前位置之间的数据)复制到缓冲区起始位置,并重置读写指针。调用后,position 变为剩余未读数据的长度,limit 变为 capacity,此时可直接向缓冲区写入新数据而不会覆盖尚未发送或处理的旧数据。

compact() 如何移动未读数据并重置指针
该方法通过内部数组拷贝实现数据迁移。它将当前 position 到 limit 之间的字节块整体前移至索引 0 处,随后更新 position 为原剩余量,limit 设为容量上限。这一操作确保后续写入从头部开始,同时保留需要继续处理的数据。

import java.nio.ByteBuffer;
public class CompactDemo {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10);
// 写入 "ABC"
buffer.put((byte)'A');
buffer.put((byte)'B');
buffer.put((byte)'C');
// 模拟读取:flip 后 position=0, limit=3
buffer.flip();
System.out.println("Before compact: pos=" + buffer.position() + ", lim=" + buffer.limit());
// 只读取第一个字节 'A'
byte b = buffer.get();
System.out.println("Read: " + (char)b);
// 此时 position=1, limit=3,剩余 "BC"
// 调用 compact 将 "BC" 移到开头
buffer.compact();
System.out.println("After compact: pos=" + buffer.position() + ", lim=" + buffer.limit());
// 继续写入新数据
buffer.put((byte)'D');
buffer.put((byte)'E');
// 再次 flip 准备读取
buffer.flip();
while(buffer.hasRemaining()) {
System.out.print((char)buffer.get());
}
System.out.println(); // 输出 BCDE
}
}
运行上述代码,输出结果为:
Before compact: pos=0, lim=3
Read: A
After compact: pos=2, lim=10
BCDE
可见,compact() 成功保留了未读的 "BC",并在其后追加了 "DE",最终得到 "BCDE"。
compact() 与 clear() 的区别及适用场景
clear() 直接重置 position=0、limit=capacity,丢弃所有未读数据;而 compact() 仅移动未读部分,适用于半包读取或流式处理中需保留部分内容的场景。例如在网络通信中,若接收到的数据包不完整,使用 compact() 可避免重新组装数据。

import java.nio.ByteBuffer;
public class ClearVsCompact {
public static void main(String[] args) {
ByteBuffer buf = ByteBuffer.allocate(5);
buf.put((byte)1).put((byte)2).put((byte)3); // 写入 1,2,3
buf.flip(); // position=0, limit=3
// 情况1:使用 clear()
ByteBuffer bufClear = (ByteBuffer) buf.duplicate();
bufClear.get(); // 读掉 1
bufClear.clear(); // position=0, limit=5,数据丢失
bufClear.put((byte)4).put((byte)5);
bufClear.flip();
System.out.print("Clear result: ");
while(bufClear.hasRemaining()) System.out.print(bufClear.get() + " ");
System.out.println(); // 输出 4 5 ,原始 2,3 丢失
// 情况2:使用 compact()
ByteBuffer bufCompact = (ByteBuffer) buf.duplicate();
bufCompact.get(); // 读掉 1
bufCompact.compact(); // 2,3 移到前两位,position=2
bufCompact.put((byte)4).put((byte)5);
bufCompact.flip();
System.out.print("Compact result: ");
while(bufCompact.hasRemaining()) System.out.print(bufCompact.get() + " ");
System.out.println(); // 输出 2 3 4 5 ,保留未读数据
}
}
对比结果显示:clear() 导致中间数据永久丢失,适合完全清空重填;compact() 保留有效载荷,适合增量处理。选择依据是是否需要维持数据连续性。
compact() 后 position 和 limit 的具体数值变化
假设初始状态:capacity=10, position=3, limit=7,表示有 4 个字节待处理(索引 3~6)。调用 compact() 后,这 4 个字节被复制到索引 0~3,position 更新为 4(即剩余数量),limit 更新为 10。此时缓冲区可写入最多 6 个新字节(10-4=6)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











