ByteBuffer

ByteBuffer的常用属性

1.position 标识下一个byte的操作位

2.limit 标识上界

3.capacity 标识容量

4.mark 辅助标识

 

ByteBuffer的常用函数

 

ByteBuffer.allocate(250) -- 新建byteBuffer

bb.wrap(new byte[100]) -- 新建byteBuffer

 

put方法写 -- 入缓冲区

get方法  -- 读取缓冲区

 

flip方法 反转 -- 用于从写入到读取的操作,将position为0,limit为原position

 

compact方法 --  压缩,舍弃position之前的内容

 

mark()  --  标志position

reset() --  重新设置position为当初的mark值

<think>嗯,用户想了解Java NIO ByteBuffer的使用方法和常见问题。从引用的内容来看,ByteBuffer是Java NIO中处理字节数据的核心类,用户可能需要具体的使用示例和常见问题解决方案。 用户可能正在开发需要高效I/O操作的应用,比如网络通信或文件处理。从引用中可以看出ByteBuffer有几个关键特性:字节序控制、内存分配方式(堆内/堆外)、状态切换(flip/clear/compact)等。这些应该是回答的重点。 考虑到用户可能是中级Java开发者,需要避免过于基础的JVM知识,但要强调容易出错的操作点。比如状态切换的flip-clear-compact三部曲,很多开发者容易在这里出错。引用[4]中的API说明很详细,可以作为方法讲解的基础。 常见问题部分需要结合实践中的坑:比如字节序导致的数据解析错误、忘记flip造成的读取异常、内存泄漏等。特别是堆外内存管理,这个在引用中没有充分展开,但实际开发中很重要。 示例代码要覆盖基本使用场景:初始化、写入、读取、状态转换。可以增加一个网络通信中的字节打包解包示例,因为引用[1]提到这是ByteBuffer的典型应用场景。 最后的相关问题设计要引导用户深入:性能优化、内存管理、替代方案比较等。特别是与Netty的ByteBuf对比,很多NIO开发者最终会转向Netty,这个过渡值得探讨。</think>以下是Java NIO `ByteBuffer` 的详细使用方法和常见问题解析: ### 一、核心概念 1. **缓冲区结构** `ByteBuffer` 内部通过四个属性管理数据: - **`capacity`**:缓冲区总容量(创建后不可变) - **`position`**:当前读写位置(初始为0) - **`limit`**:可读写数据边界(初始等于`capacity`) - **`mark`**:临时标记位置(通过`mark()`设置) 2. **字节序控制** 通过`order(ByteOrder)`方法设置字节序(默认与系统一致): ```java buffer.order(ByteOrder.LITTLE_ENDIAN); // 设为小端序 ``` --- ### 二、核心方法详解 #### 1. 初始化 ```java // 堆内内存(受JVM GC管理) ByteBuffer heapBuffer = ByteBuffer.allocate(1024); // 堆外内存(需手动释放,性能更高) ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); // 包装现有数组(不创建新内存) byte[] arr = new byte[256]; ByteBuffer wrappedBuffer = ByteBuffer.wrap(arr); ``` #### 2. 读写操作 ```java // 写入数据 buffer.put((byte) 0x41); // 写单个字节 buffer.put(new byte[]{0x42, 0x43}); // 写字节数组 // 读取数据 buffer.flip(); // 切换读模式(关键步骤!) byte b = buffer.get(); // 读单个字节 byte[] data = new byte[2]; buffer.get(data); // 读入数组 ``` #### 3. 状态切换 | 方法 | 作用 | 图示变化 | |------------|-----------------------------------|---------------------------| | `flip()` | 写→读模式:`limit=position; position=0` | [^4] | | `clear()` | 读→写模式:`position=0; limit=capacity` | [^4] | | `compact()`| 保留未读数据:将剩余数据复制到缓冲区头部 | [^4] | --- ### 三、常见问题及解决方案 1. **忘记调用 `flip()` 导致读取失败** ```java // 错误示例 buffer.put(data); buffer.get(); // 抛出BufferUnderflowException! // 正确:写入后必须flip() buffer.put(data); buffer.flip(); buffer.get(); // 正常读取 ``` 2. **字节序错误导致数据解析异常** ```java // 服务端(大端序) buffer.putInt(0x12345678); // 客户端(小端序读取) buffer.order(ByteOrder.LITTLE_ENDIAN); int value = buffer.getInt(); // 得到错误值 0x78563412 ``` **解决方案**:通信双方约定统一字节序。 3. **堆外内存泄漏** 直接缓冲区不会自动回收: ```java // 显式释放堆外内存(JDK9+) if (buffer.isDirect()) { ((DirectBuffer) buffer).cleaner().clean(); } ``` 4. **`compact()` 使用误区** 误以为会清空数据,实际是**压缩未读数据**: ```java buffer.put("Hello".getBytes()); buffer.flip(); buffer.get(); // 读取'H' buffer.compact(); // 此时缓冲区内容变为 "ello" + 剩余空间 ``` --- ### 四、典型应用场景 ```java // 文件读取(结合FileChannel) try (FileChannel channel = FileChannel.open(Paths.get("data.bin"))) { ByteBuffer buffer = ByteBuffer.allocate(1024); while (channel.read(buffer) > 0) { buffer.flip(); processData(buffer); // 处理数据 buffer.clear(); // 准备下一次读取 } } ``` > **关键提示**: > - 堆内缓冲区适合生命周期短的数据 > - 堆外缓冲区减少JVM堆压力,适合大文件或网络I/O[^1][^3] > - 频繁读写时优先使用`ByteBuffer.allocateDirect()`
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值