java nio中buffer通过子类静态方法创建,典型流程为写入→翻转→读取→清空;关键指针position、limit、capacity控制读写边界,flip重置读模式,clear重置写模式,compact用于部分读取后继续写入。

Java 中的 Buffer(缓冲区)是 NIO 的核心组件之一,主要用于在 Channel 和程序之间高效传输数据。它不是直接用 new 创建的普通对象,而是通过其子类(如 ByteBuffer、CharBuffer 等)提供的静态工厂方法来创建。读写操作需遵循“写入 → 翻转 → 读取 → 清空”的典型流程。
如何创建 Buffer
最常用的是 ByteBuffer,其他类型(IntBuffer、CharBuffer 等)用法类似:
-
allocate(int capacity):在 JVM 堆内存中分配缓冲区,例如
ByteBuffer buf = ByteBuffer.allocate(1024); -
allocateDirect(int capacity):分配堆外内存(Direct Buffer),I/O 性能更高,但创建成本略高,适合频繁 I/O 场景,例如
ByteBuffer buf = ByteBuffer.allocateDirect(1024); -
wrap(byte[] array):包装已有字节数组,不复制数据,数组修改会影响 buffer,例如
ByteBuffer buf = ByteBuffer.wrap(new byte[]{1,2,3}); - 文件或字符串转 Buffer 可先转为字节数组再 wrap,如
ByteBuffer.wrap("hello".getBytes(StandardCharsets.UTF_8))
Buffer 的基本读写流程
Buffer 内部有三个关键指针:position(当前读写位置)、limit(读/写边界)、capacity(总容量)。它们的关系决定了数据能否读写成功。
-
写入阶段:调用
put(...)方法,position 自动后移;写完后必须调用flip()—— 它将 limit 设为当前 position,position 归零,为读做准备 -
读取阶段:调用
get()或get(byte[] dst),position 向前推进;读到 limit 就停止 -
重用缓冲区:读完若要再次写入,可调用
clear()(重置 position=0、limit=capacity,但不清数据)或compact()(把未读数据移到开头,position 设为已读长度,适合部分读取后继续写入)
常见读写操作示例
以 ByteBuffer 为例,演示一次完整写→读循环:
ByteBuffer buf = ByteBuffer.allocate(8);
buf.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o'); // 写入5字节
System.out.println("写后 position=" + buf.position()); // 输出 5
<p>buf.flip(); // 准备读
byte[] dst = new byte[5];
buf.get(dst); // 读出5字节
System.out.println(new String(dst)); // 输出 "Hello"
System.out.println("读后 position=" + buf.position()); // 输出 5</p><p>buf.clear(); // 重置,可再次写入
</p>
注意事项与技巧
实际使用中容易忽略的关键点:
- Buffer 是线程不安全的,多线程需各自持有独立实例或加锁
- 调用
get()或put()超出 limit 会抛 BufferUnderflowException 或 BufferOverflowException - 判断是否还有数据可读:用
hasRemaining(),等价于position - 获取当前可读字节数:用
remaining(),即limit - position - 如果需要从头重新读,可用
rewind()(position=0,limit 不变),适用于重复解析同一段数据
理解 position、limit、capacity 三者关系,掌握 flip/clear/compact 的适用场景,就能稳妥地用好 Java NIO Buffer。不复杂但容易忽略细节,多练几次就自然了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











