当前位置: 首页 > news >正文

NIO ByteBuffer 总结

目录

  • 基本概念
  • 创建 ByteBuffer
  • 核心属性
  • 关键方法
    • 切换模式
    • 读写操作
    • 压缩数据

基本概念

java.nio.ByteBuffer 是 Java NIO 中一个核心类, 用于高效处理二进制数据的读写操作。应用于通道(Channel)的I/O操作。作用:

  • 数据缓冲:作为内存中的临时存储区,用于在通道Channel(如文件或网络通道)之间传输数据。
  • 简化数据处理:支持对基本数据类型(如int、char)的直接读写。
  • 高效操作:提供直接内存访问(Direct Buffer),减少数据在JVM堆和本地内存之间的复制开销。

创建 ByteBuffer

(1)堆缓冲区(Heap Buffer)

ByteBuffer buffer = ByteBuffer.allocate(1024); // 在JVM堆上分配

源码:

// java.nio.ByteBuffer
public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity); // 堆分配
}

class HeapByteBuffer extends ByteBuffer
{
    HeapByteBuffer(int cap, int lim) {
        super(-1, 0, lim, cap, new byte[cap], 0);
        /*
        hb = new byte[cap]; -- 底层是字节数组
        offset = 0;         -- 偏移量初始 0
        */
}

(2)直接缓冲区(Direct Buffer)

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); // 直接在本地内存分配

源码:

// java.nio.ByteBuffer
public static ByteBuffer allocateDirect(int capacity) {
    return new DirectByteBuffer(capacity); // 本地内存分配
}

// ... 

(3)包装数组(wrap)

byte[] bytes = new byte[1024];
ByteBuffer wrappedBuffer = ByteBuffer.wrap(bytes); // 包装现有数组

核心属性

ByteBuffer通过四个属性控制读写操作:

  • Capacity:缓冲区容量(不可变)。
  • Position:当前读写位置,下一个操作的起始索引。
  • Limit:可操作数据的最大位置(写模式时等于Capacity,读模式时等于有效数据量)。
  • Mark:标记位置,后续可通过reset()返回到此位置;
// 继承了 java.nio.Buffer
public abstract class ByteBuffer extends Buffer 
    implements Comparable<ByteBuffer>{
    
    ...
    
    final byte[] hb;                  // Non-null only for heap buffers
    final int offset;
    boolean isReadOnly;                 // Valid only for heap buffers
    
    ByteBuffer(int mark, int pos, int lim, int cap,   // package-private
                 byte[] hb, int offset)
    {
        super(mark, pos, lim, cap);
        this.hb = hb;
        this.offset = offset;
    }
    
    ...
    
}

// 父类 java.nio.Buffer
public abstract class Buffer {

    ...

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity;
    
    // 返回 mark 标记位置
    public final Buffer reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }
    
    ... 
    
}

关键方法

切换模式

(1)flip():写模式 → 读模式(limit=position,position=0)。

/** 
 * java.nio.Buffer 父类中实现, 
 
 * 使用示例 :
 * buf.put(magic);    // Prepend header
 * in.read(buf);      // Read data into rest of buffer
 * buf.flip();        // Flip buffer
 * out.write(buf);    // Write header + data to channel</pre></blockquote>
 */
public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

(2)clear():读模式 → 写模式(position=0,limit=capacity,数据未删除)。

/**
 * Clears this buffer.  The position is set to zero, the limit is set to
 * the capacity, and the mark is discarded.
 *
 * <p> Invoke this method before using a sequence of channel-read or
 * <i>put</i> operations to fill this buffer.  For example:
 *
 * <blockquote><pre>
 * buf.clear();     // Prepare buffer for reading
 * in.read(buf);    // Read data</pre></blockquote>
 *
 * <p> This method does not actually erase the data in the buffer, but it
 * is named as if it did because it will most often be used in situations
 * in which that might as well be the case. </p>
 */
public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

(3)rewind():重置position为0,用于重新读取数据。

/**
 * Rewinds this buffer.  The position is set to zero and the mark is
 * discarded.
 *
 * <p> Invoke this method before a sequence of channel-write or <i>get</i>
 * operations, assuming that the limit has already been set
 * appropriately.  For example:
 *
 * <blockquote><pre>
 * out.write(buf);    // Write remaining data
 * buf.rewind();      // Rewind buffer
 * buf.get(array);    // Copy data into array</pre></blockquote>
 *
 * @return  This buffer
 */
public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}

读写操作

(1)put(byte b)get():相对位置操作(自动移动position)。

java.nio.ByteBuffer 抽象方法:

public abstract class ByteBuffer extends Buffer 
    implements Comparable<ByteBuffer>{
    ...
    
    public abstract byte get(); // 抽象方法
    
    public abstract ByteBuffer put(byte b); // 抽象方法
    
    ...
}

具体实现类:java.nio.HeapByteBuffer / java.nio.DirectByteBuffer

// java.nio.HeapByteBuffer
public byte get() {
    return hb[ix(nextGetIndex())];
}

public ByteBuffer put(byte x) {
    hb[ix(nextPutIndex())] = x;
    return this;
}

final int nextGetIndex() {                          // package-private
    int p = position;
    if (p >= limit)
        throw new BufferUnderflowException();
    position = p + 1;
    return p;
}

final int nextPutIndex() {                          // package-private
    int p = position;
    if (p >= limit)
        throw new BufferOverflowException();
    position = p + 1;
    return p;
}

(2)put(int index, byte b)get(int index):绝对位置操作(不移动position)。

// java.nio.HeapByteBuffer
public byte get(int i) {
    return hb[ix(checkIndex(i))];
}

public ByteBuffer put(int i, byte x) {
    hb[ix(checkIndex(i))] = x;
    return this;
}

// java.nio.Buffer
final int checkIndex(int i) {                       // package-private
    if ((i < 0) || (i >= limit))
        throw new IndexOutOfBoundsException();
    return i;
}

压缩数据

compact():将未读数据复制到缓冲区头部,position设置为剩余数据末尾,继续写入。

java.nio.ByteBuffer 抽象方法:

public abstract ByteBuffer compact();

具体实现类:java.nio.HeapByteBuffer / java.nio.DirectByteBuffer

// java.nio.HeapByteBuffer
public ByteBuffer compact() {
    // 未读数据复制到缓冲区头部
    System.arraycopy(hb, ix(position()), hb, ix(0), remaining()); 
    // position设置为剩余数据末尾
    position(remaining());
    // limit设置为容量,支持继续写入
    limit(capacity());
    discardMark();
    return this;
}

相关文章:

  • WPF控件DataGrid介绍
  • Ubuntu常用命令大全 | 零基础快速上手指南
  • Python环境安装
  • 【C++】内存管理
  • Github 2025-03-23 php开源项目日报Top10
  • MySQL中的锁(全局锁、表锁和行锁)
  • Java19虚拟线程原理详细透析以及企业级使用案例。
  • SpringMVC 的面试题
  • Python Cookbook-4.11 在无须过多援引的情况下创建字典
  • CICDDevOps概述
  • PID参数整定:从“炼丹术士“到“系统调音师“的进化指南
  • SVN忽略不必提交的文件夹和文件方法
  • 网络基础(二)
  • 一文解读DeepSeek在法律商业仲裁细分行业的应用
  • 麒麟Win32运行环境
  • 【蓝桥杯速成】| 10.回溯切割
  • Spring Boot(十七):集成和使用Redis
  • 【正点原子】AI人工智能深度学习(RV1126/RK3568/RK3588)-第1期 准备篇
  • 【Android】VehiclePropertyAccess引起CarService崩溃
  • AI比人脑更强,因为被植入思维模型【21】冯诺依曼思维模型
  • 深圳下调公积金利率,209万纯公积金贷款总利息减少9.94万
  • 现场|万里云端,遇见上博
  • 哥伦比亚总统称将在访华期间签署“一带一路”倡议意向书,外交部回应
  • 央行行长:未来还可以扩大结构性货币政策工具规模或创设新的政策工具
  • 奥迪4S店内揭车衣时遭“连环车损”,双方因赔偿分歧陷僵局
  • 赵乐际:深入学习贯彻习近平生态文明思想,推动森林法全面有效贯彻实施