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 负责处理所有网络数据的读写操作,是实现高性能通信的基础。

相关推荐
yongche_shi几秒前
ragas官方文档中文版(五十)
开发语言·python·ai·ragas·如何评估和改进 rag 应用
前端之虎陈随易2 分钟前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
一路向北he5 分钟前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
码事漫谈7 分钟前
别写Prompt了,现在流行给AI“写循环”
后端
国强_dev25 分钟前
技术探讨:使用 stunnel 加密转发数据库连接时,如何获取客户端真实 IP?
数据库·网络协议·tcp/ip
kyriewen27 分钟前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
@insist12328 分钟前
系统规划与管理师-信息系统规划核心工作要点解析
数据库·软考·系统规划与管理师·软件水平考试·系统规划与管理工程师
超级数据查看器33 分钟前
超级数据查看器 v10.0 发布
java·大数据·数据库·sqlite·安卓
前端一小卒40 分钟前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
数安3000天1 小时前
增量数据如何自动分类分级,避免目录“过期“?
大数据·数据库