java nio 中的 buffer 是用于与通道(channel)进行数据交互的内存容器,它本质上是一个固定大小的数组,提供了结构化访问和批量传输数据的能力。要使用它,你需要通过 allocate() 方法创建实例,写入数据前调用 flip() 切换模式,读取后调用 clear() 重置状态。这种设计将内存管理与 i/o 操作解耦,允许非阻塞模式下高效地处理字节流。

Buffer 的核心属性如何协同工作
Buffer 依靠四个关键索引属性来管理数据位置:capacity 表示最大容量,limit 表示当前可操作的边界,position 表示当前读写位置,mark 记录当前位置以备恢复。在写入阶段,position 递增,limit 保持为 capacity;在读取阶段,必须先调用 flip(),此时 limit 变为原 position,position 归零,从而限制读取范围不超过已写入的数据量。

import java.nio.ByteBuffer;
public class BufferDemo {
public static void main(String[] args) {
// 分配容量为 10 的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(10);
System.out.println("初始状态:");
printState(buffer);
// 写入数据
buffer.put((byte) 'A');
buffer.put((byte) 'B');
System.out.println("写入后:");
printState(buffer);
// 切换为读模式
buffer.flip();
System.out.println("Flip 后:");
printState(buffer);
// 读取数据
byte b1 = buffer.get();
byte b2 = buffer.get();
System.out.println("读取后:");
printState(buffer);
// 清理缓冲区
buffer.clear();
System.out.println("Clear 后:");
printState(buffer);
}
private static void printState(ByteBuffer buffer) {
System.out.println("Capacity: " + buffer.capacity() +
", Limit: " + buffer.limit() +
", Position: " + buffer.position());
}
}
运行上述代码的预期输出如下: 初始状态: Capacity: 10, Limit: 10, Position: 0 写入后: Capacity: 10, Limit: 10, Position: 2 Flip 后: Capacity: 10, Limit: 2, Position: 0 读取后: Capacity: 10, Limit: 2, Position: 2 Clear 后: Capacity: 10, Limit: 10, Position: 0
直接缓冲与堆缓冲的区别是什么
Java NIO 提供两种主要的 ByteBuffer 实现:堆缓冲(Heap Buffer)和直接缓冲(Direct Buffer)。堆缓冲基于 JVM 堆内存数组构建,创建速度快但 I/O 操作涉及内核态与用户态之间的数据拷贝;直接缓冲位于堆外内存,虽然创建开销较大,但能避免额外的内存复制,适合频繁的大规模数据传输场景。选择哪种类型取决于对延迟和吞吐量的权衡。

import java.nio.ByteBuffer;
import java.io.FileOutputStream;
import java.io.IOException;
public class DirectVsHeap {
public static void main(String[] args) throws IOException {
int size = 1024 * 1024; // 1MB
// 创建堆缓冲
ByteBuffer heapBuf = ByteBuffer.allocate(size);
fillBuffer(heapBuf);
// 创建直接缓冲
ByteBuffer directBuf = ByteBuffer.allocateDirect(size);
fillBuffer(directBuf);
long startHeap = System.nanoTime();
writeToFile(heapBuf);
long endHeap = System.nanoTime();
long startDirect = System.nanoTime();
writeToFile(directBuf);
long endDirect = System.nanoTime();
System.out.println("Heap Buffer Time: " + (endHeap - startHeap) / 1000000.0 + " ms");
System.out.println("Direct Buffer Time: " + (endDirect - startDirect) / 1000000.0 + " ms");
}
private static void fillBuffer(ByteBuffer buf) {
for (int i = 0; i <p>该程序演示了两种缓冲区的写入性能差异。通常直接缓冲在文件 I/O 中表现更优,因为它减少了系统调用的数据拷贝次数。注意在实际测试中,JVM 启动预热可能会影响首次运行的结果,建议多次运行取平均值。此外,直接缓冲需要手动管理内存,超出堆限制时可能引发 <code>OutOfMemoryError</code>,而堆缓冲受 GC 管理,更安全但效率略低。</p><h2>当 <code>position</code> 等于 <code>limit</code> 时继续读取会发生什么</h2><p>当 <code>position</code> 等于 <code>limit</code> 时,缓冲区处于“空”或“耗尽”状态,此时若尝试执行读取操作如 <code>get()</code>,将抛出 <code>java.nio.BufferUnderflowException</code> 异常。这是 <code>Buffer</code> 机制的安全保护,防止越界访问未初始化或无效内存区域。开发者必须在读取前检查 <code>hasRemaining()</code> 方法返回值,确保 <code>position 后再进行数据提取,否则程序会因未捕获异常而中断。</code></p>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











