JavaSE-11-ByteBuffer(NIO核心组件)

JavaSE-11-ByteBuffer(NIO核心组件)

ByteBuffer 是 Java NIO 中非常重要的组件,用于处理字节数据。它是 Buffer 的子类,专门用于处理字节数据。本文详细解释 ByteBuffer 的各个方法和用法。

ByteBuffer的出现,将IO操作的通道channel和存储读写分离,解耦,而该类也相当于将普通的byte[]数组,包装成一个有完整属性和行为操作的数据容器模型!这种组件解耦分离封装的设计模式,值得学习!

一、UML类图

二、ByteBuffer 基本概念

ByteBuffer 有四个重要属性:

    1. capacity:缓冲区容量(固定不变)
    1. position:当前读写位置(0 <= position <= limit)
    1. limit:当前读写的限制(limit <= capacity)
    1. mark:标记位置(用于重置 position)

三、ByteBuffer 创建方法

1. allocate() - 分配堆内存缓冲区

复制代码
// 创建容量为1024的堆内存缓冲区 ByteBuffer buffer = ByteBuffer.allocate( 1024 ); System.out.println( "capacity: " + buffer.capacity()); // 1024 System.out.println( "position: " + buffer.position()); // 0 System.out.println( "limit: " + buffer.limit()); // 1024

2. allocateDirect() - 分配直接内存缓冲区

复制代码
// 创建容量为1024的直接内存缓冲区(更高效,但创建成本高) ByteBuffer directBuffer = ByteBuffer.allocateDirect( 1024 );

3. wrap() - 包装现有字节数组

复制代码
// 包装现有字节数组 byte [] data = "Hello" .getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); System.out.println( "capacity: " + buffer.capacity()); // 5 System.out.println( "position: " + buffer.position()); // 0 System.out.println( "limit: " + buffer.limit()); // 5

四、ByteBuffer 核心方法详解

1. put() - 写入数据

复制代码
ByteBuffer buffer = ByteBuffer.allocate( 10 ); // put(byte b) - 写入单个字节 buffer.put(( byte ) 'H' ); System.out.println( "position: " + buffer.position()); // 1 // put(byte[] src) - 写入字节数组 buffer.put( "ello" .getBytes()); System.out.println( "position: " + buffer.position()); // 5 // put(byte[] src, int offset, int length) - 写入字节数组的一部分 byte [] data = "World" .getBytes(); buffer.put(data, 0 , 3 ); // 只写入"Wor" System.out.println( "position: " + buffer.position()); // 8 // put(int index, byte b) - 在指定位置写入(不改变position) buffer.put( 0 , ( byte ) 'h' ); // 将第一个位置的'H'改为'h' System.out.println( "position: " + buffer.position()); // 8 (不变)

2. get() - 读取数据

复制代码
ByteBuffer buffer = ByteBuffer.wrap( "Hello" .getBytes()); // get() - 读取当前位置的字节 byte b = buffer.get(); // 读取'H' System.out.println(( char ) b); // H System.out.println( "position: " + buffer.position()); // 1 // get(byte[] dst) - 读取多个字节到数组 byte [] data = new byte [ 4 ]; buffer.get(data); // 读取"ello" System.out.println( new String (data)); // ello System.out.println( "position: " + buffer.position()); // 5 // get(byte[] dst, int offset, int length) - 读取字节到数组的指定位置 buffer.rewind(); // 重置position到0 byte [] target = new byte [ 10 ]; buffer.get(target, 2 , 3 ); // 从target[2]开始写入3个字节 System.out.println( new String (target, 2 , 3 )); // Hel // get(int index) - 读取指定位置的字节(不改变position) buffer.rewind(); byte first = buffer.get( 0 ); // 读取第一个字节 System.out.println(( char ) first); // H System.out.println( "position: " + buffer.position()); // 0 (不变)

3. flip() - 翻转缓冲区(准备读取)

复制代码
ByteBuffer buffer = ByteBuffer.allocate( 10 ); // 写入数据 buffer.put( "Hello" .getBytes()); System.out.println( "写入后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 写入后 - position: 5, limit: 10 // flip() - 翻转为读取模式 buffer.flip(); System.out.println( "翻转后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 翻转后 - position: 0, limit: 5 // 现在可以读取数据了 byte [] data = new byte [buffer.remaining()]; buffer.get(data); System.out.println( new String (data)); // Hello

4. rewind() - 重绕缓冲区

复制代码
ByteBuffer buffer = ByteBuffer.wrap( "Hello" .getBytes()); // 读取所有数据 byte [] data = new byte [buffer.remaining()]; buffer.get(data); System.out.println( new String (data)); // Hello System.out.println( "position: " + buffer.position()); // 5 // rewind() - 重置position为0,limit不变 buffer.rewind(); System.out.println( "重绕后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 重绕后 - position: 0, limit: 5 // 可以重新读取数据 byte [] data2 = new byte [buffer.remaining()]; buffer.get(data2); System.out.println( new String (data2)); // Hello

5. clear() - 清空缓冲区

复制代码
ByteBuffer buffer = ByteBuffer.allocate( 10 ); buffer.put( "Hello" .getBytes()); System.out.println( "写入后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 写入后 - position: 5, limit: 10 // clear() - 清空缓冲区(实际只是重置position和limit) buffer.clear(); System.out.println( "清空后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 清空后 - position: 0, limit: 10 // 缓冲区中的数据实际上还在,只是被标记为可覆盖 buffer.put( "World" .getBytes()); // 现在缓冲区中是"World",但原来的数据可能还在内存中

6. compact() - 压缩缓冲区

复制代码
ByteBuffer buffer = ByteBuffer.allocate( 10 ); buffer.put( "HelloWorld" .getBytes()); buffer.flip(); // 准备读取 // 读取部分数据 byte [] first5 = new byte [ 5 ]; buffer.get(first5); System.out.println( new String (first5)); // Hello System.out.println( "读取后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 读取后 - position: 5, limit: 10 // compact() - 压缩缓冲区,将未读数据移到开头 buffer.compact(); System.out.println( "压缩后 - position: " + buffer.position() + ", limit: " + buffer.limit()); // 输出: 压缩后 - position: 5, limit: 10 // 缓冲区中现在是"World"在开头,后面是空位

7. remaining() 和 hasRemaining() - 检查剩余数据

复制代码
ByteBuffer buffer = ByteBuffer.wrap( "Hello" .getBytes()); System.out.println( "remaining: " + buffer.remaining()); // 5 System.out.println( "hasRemaining: " + buffer.hasRemaining()); // true buffer.get( new byte [ 3 ]); // 读取3个字节 System.out.println( "remaining: " + buffer.remaining()); // 2 System.out.println( "hasRemaining: " + buffer.hasRemaining()); // true buffer.get( new byte [ 2 ]); // 读取剩余2个字节 System.out.println( "remaining: " + buffer.remaining()); // 0 System.out.println( "hasRemaining: " + buffer.hasRemaining()); // false

五、ByteBuffer 在聊天室中的应用

1. 服务端读取客户端消息

复制代码
/** * 处理客户端消息 - 你的代码中的应用 */ private void handleRead (SelectionKey key) throws IOException { SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate( 1024 ); // 读取数据到缓冲区 int bytesRead = clientChannel.read(buffer); if (bytesRead > 0 ) { // flip() - 翻转缓冲区,准备读取 buffer.flip(); // remaining() - 检查有多少数据可读 byte [] data = new byte [buffer.remaining()]; // get() - 读取所有剩余数据 buffer.get(data); String message = new String (data).trim(); System.out.println( "收到消息: " + message); // 处理消息... } }

2. 服务端发送消息给客户端

复制代码
/** * 广播消息给所有客户端 - 你的代码中的应用 */ private void broadcastMessage (String username, String message) throws IOException { String formattedMessage = "[" + username + "]: " + message; System.out.println(formattedMessage); // wrap() - 包装字符串为ByteBuffer ByteBuffer buffer = ByteBuffer.wrap(formattedMessage.getBytes()); for (SocketChannel channel : clientMap.keySet()) { // rewind() - 重置position,因为要多次发送给不同客户端 buffer.rewind(); channel.write(buffer); } }

3. 客户端发送消息

复制代码
/** * 发送消息到服务端 - NIOChatClient中的应用 */ private void sendMessage (String message) { try { // wrap() - 包装消息为ByteBuffer ByteBuffer buffer = ByteBuffer.wrap((message + "\n" ).getBytes()); // write() - 发送缓冲区中的数据 socketChannel.write(buffer); } catch (IOException e) { e.printStackTrace(); } }

六、ByteBuffer 状态管理示例

复制代码
public class ByteBufferStateExample { public void demonstrateBufferStates () { ByteBuffer buffer = ByteBuffer.allocate( 10 ); System.out.println( "初始状态: position=" + buffer.position() + ", limit=" + buffer.limit() + ", capacity=" + buffer.capacity()); // 1. 写入模式 buffer.put( "Hello" .getBytes()); System.out.println( "写入后: position=" + buffer.position() + ", limit=" + buffer.limit()); // 2. 准备读取 - flip() buffer.flip(); System.out.println( "翻转后: position=" + buffer.position() + ", limit=" + buffer.limit()); // 3. 读取部分数据 byte [] partial = new byte [ 3 ]; buffer.get(partial); System.out.println( "部分读取后: position=" + buffer.position() + ", limit=" + buffer.limit()); // 4. 压缩缓冲区 - compact() buffer.compact(); System.out.println( "压缩后: position=" + buffer.position() + ", limit=" + buffer.limit()); // 5. 清空缓冲区 - clear() buffer.clear(); System.out.println( "清空后: position=" + buffer.position() + ", limit=" + buffer.limit()); } }

七、ByteBuffer 类型转换方法

复制代码
public class ByteBufferTypeConversion { public void demonstrateTypeMethods () { ByteBuffer buffer = ByteBuffer.allocate( 20 ); // 写入各种类型数据 buffer.putInt( 123456 ); // 4字节 buffer.putLong( 987654321L ); // 8字节 buffer.putDouble( 3.14159 ); // 8字节 buffer.putChar( 'A' ); // 2字节 // 准备读取 buffer.flip(); // 按相同顺序读取 int intValue = buffer.getInt(); long longValue = buffer.getLong(); double doubleValue = buffer.getDouble(); char charValue = buffer.getChar(); System.out.println( "int: " + intValue); // 123456 System.out.println( "long: " + longValue); // 987654321 System.out.println( "double: " + doubleValue); // 3.14159 System.out.println( "char: " + charValue); // A } }

ByteBuffer 是 NIO 的核心组件,正确理解和使用它的各种方法对于编写高效的 NIO 程序至关重要。聊天室应用中,ByteBuffer 负责处理所有网络数据的读写操作,是实现高性能通信的基础。

相关推荐
Hilaku9 小时前
从 15MB 减到 800KB,一行 ffmpeg 解决3D 渲染卡顿问题
前端·javascript·程序员
春栀怡铃声9 小时前
【C++修仙录02】筑基篇:vector 使用
开发语言·c++·算法
茉莉玫瑰花茶9 小时前
LangGraph 持久化(Persistence)[ 2 ]
开发语言·python·ai·langgraph
Dxy123931021610 小时前
`...` 展开运算符(Spread Operator)详解
开发语言·javascript
丁劲犇10 小时前
使用TraeAI开发Web页面测试MSYS2 ucrt64 Qt MCP服务器
服务器·前端·c++·qt·mcp
一切顺势而行10 小时前
easysearch 安装
spring·spring cloud·微服务
刀法如飞10 小时前
《理解道德经》简单版-第 1 章:道可道,非常道
前端·后端·面试
有味道的男人10 小时前
AI 对接 1688 图搜接口|Open Claw 以图搜货实战
开发语言·python
天蓝色的鱼鱼10 小时前
尤雨溪亲自点赞!用 Vue 3 写原生 App,这个框架终于来了!
前端·vue.js