ByteBuffer 主要方法详解
一、创建和分配
二、缓冲区状态属性
java
// 四个关键属性
capacity: 缓冲区总容量,创建时固定,不可变
position: 当前位置,下一个读写操作的索引
limit: 读写限制,position不能超过limit
mark: 标记位置,可标记后回到此位置三、读写数据方法
1. 读取方法
2. 写入方法
四、位置操作方法
1. 基础操作
java
// 设置位置
position(int newPosition) // 设置当前位置
limit(int newLimit) // 设置限制位置
// 查询
remaining() // 返回剩余可读/可写字节数:limit - position
hasRemaining() // 检查是否还有剩余字节2. 模式切换
java
// 写入模式 → 读取模式
flip(): // limit=position, position=0, 清除mark
// 重新开始读取
rewind(): // position=0, 保留limit, 清除mark
// 准备再次写入
clear(): // position=0, limit=capacity, 清除mark
// 不清除数据,只是重置指针
// 读取模式 → 写入模式(保留未读数据)
compact(): // 将未读数据复制到开头,position=剩余数据量,limit=capacity
// 用于处理粘包五、标记和重置
java
mark(): // 标记当前位置
reset(): // 返回到mark的位置(mark必须已设置)六、重要转换方法
七、实际使用示例
1. 基本读写流程
java
// 写入数据
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.putInt(100); // 写入int,position移动4
buffer.put("Hello".getBytes());
// 切换到读取模式
buffer.flip();
// 读取
int num = buffer.getInt(); // 读取int
byte[] strBytes = new byte[5];
buffer.get(strBytes); // 读取字符串2. 处理网络数据(粘包拆包)
java
public void decode(ByteBuffer buffer) {
while (buffer.remaining() >= 4) { // 确保有长度字段
buffer.mark(); // 标记当前位置
int length = buffer.getInt(); // 读取消息长度
if (buffer.remaining() < length) {
// 数据不完整,重置并等待
buffer.reset();
break;
}
// 读取完整消息
byte[] data = new byte[length];
buffer.get(data);
processMessage(data);
// 如果有剩余数据,继续处理(处理粘包)
if (buffer.hasRemaining()) {
// 继续循环处理下一个消息
}
}
// 压缩缓冲区,保留未处理数据
buffer.compact();
}3. 使用slice处理部分数据
java
ByteBuffer buffer = ByteBuffer.allocate(100);
// ... 填充数据
buffer.flip();
// 处理前10字节
buffer.limit(10);
ByteBuffer header = buffer.slice(); // 创建共享数据的子缓冲区
processHeader(header);
// 处理剩余数据
buffer.position(10);
buffer.limit(buffer.capacity());
ByteBuffer body = buffer.slice();
processBody(body);八、内存管理和性能提示
直接缓冲区 vs 堆缓冲区
直接缓冲区:I/O操作更快,适合网络编程
堆缓冲区:创建和回收更快,适合小数据
避免频繁分配
使用
clear()和compact()重用缓冲区对于已知最大消息大小,预分配足够缓冲区
批量操作
使用
get(byte[])比循环get()更高效使用
slice()避免数据复制
九、常见陷阱
忘记flip():写入后直接读取会得到空数据
position超过limit:会导致BufferUnderflowException
直接缓冲区无array():调用
array()会抛出UnsupportedOperationException未检查remaining():可能导致读取不完整数据
这些方法在您的协议解析代码中都非常重要,特别是compact()、slice()、remaining()等方法对于处理网络数据流中的拆包粘包问题至关重要。