Java io.netty.buffer.ByteBuf
ByteBuf 与 ByteBuffer 核心区别:Netty 对 JDK NIO 的优化升级
io.netty.buffer.ByteBuf 是 Netty 基于 JDK NIO 的 java.nio.ByteBuffer 设计的增强型缓冲区,核心目标是解决 ByteBuffer 的易用性、功能局限性问题,同时适配 Netty 的高性能网络编程场景。二者的本质差异体现在设计理念、易用性、功能扩展、性能优化四个维度,以下是详细对比:
一、核心区别总览表
| 对比维度 | ByteBuffer(JDK NIO) | ByteBuf(Netty) |
|---|---|---|
| 读写模式切换 | 需手动调用 flip()(写转读)、clear()/compact()(读转写),易出错 |
读写指针分离(readerIndex/writerIndex),无需切换,天然支持顺序读写 |
| 容量动态扩展 | 固定容量,扩容需手动创建新缓冲区并拷贝数据 | 支持动态扩容(默认按 2 倍增长,可自定义策略),自动处理容量不足 |
| 操作便捷性 | API 繁琐(如 getInt() 需手动控制偏移量),无内置工具方法 |
提供丰富的读写方法(readInt()/writeInt()、readBytes()/writeBytes()),支持字符串、数组、其他缓冲区直接读写 |
| 零拷贝支持 | 仅支持基础的 slice()/duplicate()(共享底层数据),功能有限 |
原生支持复合缓冲区(CompositeByteBuf)、Unpooled.wrappedBuffer() 等,彻底避免数据拷贝,提升网络传输性能 |
| 内存管理 | 仅支持堆内存(HeapByteBuffer)和直接内存(DirectByteBuffer),无池化机制 |
支持堆内存、直接内存,且内置内存池(PooledByteBuf) ,减少 GC 压力,提升高并发场景性能 |
| 索引访问 | 仅有一个 position 指针,读写需手动计算偏移量 |
支持绝对索引(getInt(int index))和相对索引(readInt()),读写互不干扰 |
| 可丢弃字节处理 | 需手动调用 compact() 压缩缓冲区(拷贝有效数据) |
直接调用 discardReadBytes(),无需拷贝,仅调整 readerIndex,高效回收已读空间 |
| 标记与重置 | 仅支持一个 mark 和 reset,且受模式切换影响 |
支持多个标记(MarkAware),且标记与读写指针独立,不受操作影响 |
| 适用场景 | 基础 NIO 编程,简单缓冲区操作 | Netty 网络编程、高性能 IO 场景,需频繁读写 / 扩容 / 零拷贝的场景 |
二、示例代码ByteBuffer
import java.nio.ByteBuffer; public class ByteBufferDemo { public static void main(String[] args) { // 初始化容量为10的缓冲区 ByteBuffer buf = ByteBuffer.allocate(10); // 1. 写数据:position从0→4 buf.putInt(12345); System.out.println("写后position: " + buf.position()); // 输出4 // 2. 必须手动flip()切换为读模式,否则读不到数据 buf.flip(); System.out.println("flip后position: " + buf.position()); // 输出0 // 3. 读数据:position从0→4 int value = buf.getInt(); System.out.println("读取的值: " + value); // 输出12345 // 4. 读完要重新写,需手动clear() buf.clear(); } }
三、示例代码ByteBuf
import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; public class ByteBufDemo { public static void main(String[] args) { // 初始化容量为10的缓冲区 ByteBuf buf = Unpooled.buffer(10); // 1. 写数据:writerIndex从0→4 buf.writeInt(12345); System.out.println("写后writerIndex: " + buf.writerIndex()); // 输出4 // 2. 直接读,无需切换:readerIndex从0→4 int value = buf.readInt(); System.out.println("读取的值: " + value); // 输出12345 // 3. 直接继续写,无需清空 buf.writeLong(67890L); } }
四、转十六进制输入
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; public class ByteBufHexPrint { public static void main(String[] args) { // 1. 创建一个测试用的ByteBuf并写入数据 ByteBuf buf = Unpooled.buffer(); // 写入一些测试数据:字符串"Netty" + 整数123 buf.writeBytes("Netty".getBytes()); buf.writeInt(123); // 2. 方式1:打印整个ByteBuf的十六进制(最常用) String hexStr = ByteBufUtil.hexDump(buf); System.out.println("完整ByteBuf的十六进制:"); System.out.println(hexStr); // 输出:4e657474790000007b // 3. 方式2:打印指定区间的十六进制(比如只打印前5个字节) String partialHexStr = ByteBufUtil.hexDump(buf, 0, 5); System.out.println("\n前5个字节的十六进制:"); System.out.println(partialHexStr); // 输出:4e65747479(对应"Netty") // 4. 方式3:带格式的十六进制(每行固定长度,更易读) System.out.println("\n带格式的十六进制(调试友好):"); printHexDump("测试ByteBuf", buf); } /** * 封装一个通用方法,打印带格式的十六进制(包含偏移量、十六进制、ASCII码) */ public static void printHexDump(String title, ByteBuf buf) { // hexDump方法重载:支持指定标题,自动格式化输出 System.out.println(ByteBufUtil.hexDump(title, buf)); } }
有些事情,没经历过不知道原理,没失败过不明白奥妙,没痛苦过不了解真谛。临渊羡鱼,不如退而结网!

浙公网安备 33010602011771号