NIO - ByteBuffer

分类

  1. HeapByteBuffer:基于 JVM 堆内存的字节缓冲区。
  2. DirectByteBuffer:基于系统直接内存的字节缓冲区,内部通过 Unsafe 类实现操作系统直接内存。

属性

  1. position:当前位置
  2. limit:操作边界
  3. capacity:容量
  4. mark:标记此时的 position

创建

默认将 pos 指向0,cap 与 lim 指向容器尾部。
allocate
与 allocate 相似,同时会初始化缓冲区内的数据,且不会因为初始数据而导致指针发生变化。
wrap

写入

每次写入会使 pos 指向下一个可操作位。
put

读取

ByteBuffer buf = ByteBuffer.allocate(5);
buf.put(new byte[] {'A', 'B', 'C', 'D', 'E'});
buf.flip(); // flip 方法后面会详细说到

1. array():返回缓冲区中的字节数组

byte[] bufArr = buf.array();
System.out.println(Arrays.toString(bufArr)); // [65, 66, 67, 68, 69]

2. get() / get(i)

get(i) 方法会直接从缓冲区中的字节数组取值。

get() 方法稍有差异,会将当前的 pos 作为索引到字节数组中取值,并更新 pos 使其自增一指向下一位。

get(i)

3. 获取基础属性

buf.position();
buf.capacity();
buf.limit();

4. 获取剩余

buf.remaining();
public final int remaining() {
    int rem = limit - position;
    return rem > 0 ? rem : 0;
}

buf.hasRemaining();
public final boolean hasRemaining() {
    return position < limit;
}

通过 hasRemaining() 配合 get() 即可迭代整个缓冲区

while (buf.hasRemaining()) {
    System.out.print((char) buf.get() + "\t");
}

重置

其他很多博客都提出了读、写的概念,来操作缓冲区。不过个人觉得,不如直接理解方法的实际操作,了解其实现。不仅记忆的更深,使用时心里也清楚到底更改了哪些属性。也会明白,为什么不调用某些方法就操作不到容器数据。反之为什么调用了某些方法,就可以操作容器数据。

1. flip

重置指针,准备操作缓冲区当前 [0, pos] 区间。进行读取或者写入,取决于调用者。

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

例子,迭代缓冲区的内容:

ByteBuffer buf = ByteBuffer.allocate(5);
buf.put(new byte[]{'A', 'B', 'C', 'D', 'E'});
System.out.println(buf); // java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]

// buf.flip();

while (buf.hasRemaining()) {
    System.out.print((char) buf.get() + "\t");
}

不会打印任何容器数据,因为 put 方法会变更 pos 的位置。当添加了五个字符后,缓冲区的各个指针:[pos=5 lim=5 cap=5]。那么当调用 hasRemaining 时,会检测 pos 已经处于 limit 位并返回 false。若强制直接调用 get ,也会抛出溢出异常。

调用 flip 方法重置各个指针,表示我要操作 [0, 此时的 pos] 区间数据,而此时的 pos 也由于 put 的原因指向了最后。这样就可以正常迭代了。

2. rewind
对比 flip,没有将 limit 设置为当前的 pos。

public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
}

3. clear

清除当前的指针指向,重置为初始状态。仅是调整指针,不会真正清除缓冲区中的数据。

public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

例子:

ByteBuffer buf = ByteBuffer.wrap(new byte[]{'A', 'B', 'C', 'D', 'E'});
// 迭代容器
while (buf.hasRemaining()) {
    System.out.print((char) buf.get() + "\t");
}
System.out.println();
// clear
buf.clear();
System.out.println((char) buf.get()); // A

4. compact

丢弃已经操作过的数据,将还没有操作的数据压缩到容器首部,并将 pos 的指针指向仍为操作数据的下一位。

public ByteBuffer compact() {
    System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
    position(remaining());
    limit(capacity());
    discardMark();
    return this;
}

示意图:

compact

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值