可参考之前的文章:NIO 之 ByteBuffer实现原理
下面是对之前文章的一个补充

Buffer 类 结构

对于每个非布尔原始数据类型都有一个缓冲区类。尽管缓冲区作用于它们存储的原始数据类型,但缓冲区十分倾向于处理字节。

概述

缓冲区 Buffer 内部就是用数组实现的。 Buffer 包含了下面4个属性:

  • 容量( Capacity)
    缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。
  • 上界( Limit)
    缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。
  • 位置( Position)
    下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。
  • 标记( Mark)
    一个备忘位置。调用 mark( )来设定 mark = postion。调用 reset( )设定 position = mark。标记在设定前是未定义的(undefined)。

这四个属性之间总是遵循以下关系:
0 <= mark <= position <= limit <= capacity

示例

下面展示了一个新创建的容量为 10 的 ByteBuffer 逻辑视图

ByteBuffer.allocate(10);

位置(Position)被设为 0,而且容量( Capacity)和上界( Limit)被设为 10,刚好经过缓冲区能够容纳的最后一个字节。
标记(mark)最初未定义。
容量(Capacity)是固定的,但另外的三个属性可以在使用缓冲区时改变。

put() 方法

让我们看一个例子。 我们将代表“abcde”字符串的 ASCII 码载入一个名为 buffer 的
ByteBuffer 对象中。当在图1 中所新建的缓冲区上执行以下代码后。

buffer.put((byte)'a').put((byte)'b').put((byte)'c').put((byte)'d').put((byte)'e');

缓冲区的结果状态如图 2所示:

flip() 方法

我们已经写满了缓冲区,现在我们必须准备将其清空。我们想把这个缓冲区传递给一个通
道,以使内容能被全部写出。但如果通道现在在缓冲区上执行 get(),那么它将从我们刚刚插入的有用数据之外取出未定义数据。如果我们将位置值重新设为 0,通道就会从正确位置开始获取,但是它是怎样知道何时到达我们所插入数据末端的呢?这就是上界属性被引入的目的。上界属性指明了缓冲区有效内容的末端。我们需要将上界属性设置为当前位置,然后将位置重置为 0。

flip()函数将一个能够继续添加数据元素的填充状态的缓冲区翻转成一个准备读出元素
的释放状态。在翻转之后,图 2 的缓冲区会变成图 3 中的样子。

rewind() 方法

rewind()函数与 flip()相似,但不影响上界属性。它只是将位置值设回 0。您可以使
用 rewind()后退,重读已经被翻转的缓冲区中的数据。
图2 的缓冲区调用 rewind() 方法会变成图4 中的样子。

如果将缓冲区翻转两次会怎样呢?

compact() 方法

有时,您可能只想从缓冲区中释放一部分数据,而不是全部,然后重新填充。为了实现这
一点,未读的数据元素需要下移以使第一个元素索引为 0。尽管重复这样做会效率低下,但这有时非常必要,而 API 对此为您提供了一个 compact()函数。这一缓冲区工具在复制数据时要比您使用 get()和 put()函数高效得多。所以当您需要时,请使用 compact()。图 5显示了一个读取了两个元素(position 现在为2),并且现在我们想要对其进行压缩的缓冲区。

buffer.compact();

压缩后的结果如下图

duplicate() 方法

duplicate() 方法创建了一个与原始缓冲区一样的新缓冲区。两个缓冲区共享数据,拥有同样的 capacity ,但每个缓冲区都拥有自己的 position,limit 和 mark 属性。对一个缓冲区内的数据元素所做的改变会反映在另外一个缓冲区上。这一副本缓冲区具有与原始缓冲区同样的数据视图。如果原始的缓冲区为只读,或者为直接缓冲区,新的缓冲区将继承这些属性。

    public ByteBuffer duplicate() {return new HeapByteBufferR(hb,this.markValue(),this.position(),this.limit(),this.capacity(),offset);}

重新创建一个 ByteBuffer,并且使用同一个数组。所有一个byteBuffer 变动,会影响另一个 ByteBuffer。 但 position、limit、mark 都是独立的。

duplicate() 方法

您 可 以 使 用 asReadOnlyBuffer() 函 数 来 生 成 一 个 只 读 的 缓 冲 区 视 图 。 这 与
duplicate()相同,除了这个新的缓冲区不允许使用 put(),并且其 isReadOnly()函数
将 会 返 回 true 。 对 这 一 只 读 缓 冲 区 的 put() 函 数 的 调 用 尝 试 会 导 致 抛 出
ReadOnlyBufferException 异常。

public ByteBuffer asReadOnlyBuffer() {return new HeapByteBufferR(hb,this.markValue(),this.position(),this.limit(),this.capacity(),offset);
}
HeapByteBufferR 分析
class HeapByteBufferRextends HeapByteBuffer{public ByteBuffer put(byte x) {throw new ReadOnlyBufferException();}public ByteBuffer put(int i, byte x) {throw new ReadOnlyBufferException();}public ByteBuffer putInt(int x) {throw new ReadOnlyBufferException();}......
}

HeapByteBufferR 继承 HeapByteBuffer 类,并重写了所有的可修改 buffer 的方法。把所有能修改 buffer 的方法都直接 throw ReadOnlyBufferException,来保证只读。

slice() 方法

slice() 分割缓冲区。创建一个从原始缓冲区的当前位置开始的新缓冲区,并且其容量是原始缓冲区的剩余元素数量( limit-position)。这个新缓冲区与原始缓冲区共享一段数据元素子序列。分割出来的缓冲区也会继承只读和直接属性。

原 ByteBuffer如下图:

slice() 分割后的 ByteBuffer

    public ByteBuffer slice() {return new HeapByteBuffer(hb,-1,0,this.remaining(),this.remaining(),this.position() + offset);}

想了解更多精彩内容请关注我的公众号

本人简书blog地址:http://www.jianshu.com/u/1f0067e24ff8    
点击这里快速进入简书
GIT地址:http://git.oschina.net/brucekankan/
点击这里快速进入GIT

NIO 之 Buffer 图解相关推荐

  1. 【Netty】NIO 缓冲区 ( Buffer ) ( 缓冲区读写类型 | 只读缓冲区 | 映射字节缓冲区 )

    文章目录 I . 缓冲区 ( Buffer ) 存取类型 II . 只读缓冲区 ( ReadOnlyBuffer ) III . 映射字节缓冲区 ( MappedByteBuffer ) I . 缓冲 ...

  2. java buffer nio_Java NIO之Buffer(缓冲区)入门

    ​Java NIO中的缓存区(Buffer)用于和通道(Channel)进行交互.数据是从通道读入缓冲区,从缓冲区写入到通道中的. ​缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内 ...

  3. 反射 Nio channel Buffer

    1.反射     1.反射的简介         java的反射机制 在运行状态中 对于任意一个类 都能知道任意一个类的所有属性和方法         对于任意一个对象 都能够调用它的任意一个属性和方 ...

  4. buffer java作用_Java NIO之Buffer的使用

    目录 Buffer简介 Buffer的核心属性 Buffer的创建与使用(ByteBuffer为例) 总结 参考资料 Buffer简介 缓冲区(Buffer):本质上是一个数组,用于临时保存.写入以及 ...

  5. 【Netty】NIO 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 操作

    文章目录 I . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathering 概念 II . 缓冲区 ( Buffer ) 分散 Scattering 与 聚合 Gathe ...

  6. 【Netty】NIO 缓冲区 ( Buffer ) 组件

    文章目录 I . NIO 三大核心组件 对应关系 II . 缓冲区 ( Buffer ) 类 III . 缓冲区 ( Buffer ) 机制 IV . 缓冲区 ( Buffer ) 机制 示例解析 V ...

  7. NIO的Buffer

    package com.atguigu.nio;import java.nio.IntBuffer;public class BasicBuffer {public static void main( ...

  8. Java NIO:Buffer、Channel 和 Selector

    Buffer 一个 Buffer 本质上是内存中的一块,我们可以将数据写入这块内存,之后从这块内存获取数据. java.nio 定义了以下几个 Buffer 的实现,这个图读者应该也在不少地方见过了吧 ...

  9. nio~view buffer

    此文介绍nio中ByteBuffer的特性之一,视图. *view buffer概念 ---把ByteBuffer转换为其他数据类型的buffer,比如char,long,float等,这样就方便处理 ...

最新文章

  1. 2018年摩拜校招嵌入式工程师笔试卷
  2. NR 5G NG-RAN 架 构
  3. linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架
  4. 一文看懂谷歌 NYC 算法与优化业务全景:三大项目组12个子领域详解(附重点论文下载)
  5. ubuntu php pear_ubuntu下安装pear包(lynx和php-cli安装)
  6. 论文 参考文献的格式说明
  7. Windows系统下SSH客户端连接阿里云Linux服务器
  8. 云服务器架设网站教程_阿里云服务器购买流程详细教程及注意事项
  9. 一款免费的网络时间校准小程序
  10. 学者CIO邓遵红:让人文梦想照进职业现实
  11. 查找算法之三 插值查找(C++版本)
  12. 【No.11 默认实参的匹配】
  13. android小游戏 猜拳游戏设计
  14. 计算机桌面显示器,电脑安装多显示器方法图文教程
  15. OpenCL(matmpy)
  16. python输入月份判断天数用函数的方法,python 月份天数
  17. PyTorch搭建LSTM实现时间序列预测(负荷预测)
  18. 2022年疫情下的卡塔尔世界杯,你看了么,盘点一下爆冷的赛事
  19. 界面(1):对话框和菜单 打印和按钮等杂项
  20. 机器学习char1 机器学习基础

热门文章

  1. 爬虫篇 | 快速入门selenium(十一)
  2. 从 Word2Vec 到 BERT
  3. 十年编程经验输给新晋AI工程师,6个月我们带你绝地反击
  4. 自动机器学习(AutoML)最新综述
  5. 使用PaddleFluid和TensorFlow训练RNN语言模型
  6. 【LeetCode 55】【LeetCode 45】 跳跃游戏
  7. 拉取数据_Apache Kafka-数据写入过程
  8. 【Java代码】Lamda表达式将List对象中的Map对象的key全部转化为大写或者小写【去除外层循环:可用于Map对象中的key全部转化为大写或者小写】
  9. 01 | Spring Data JPA 初识
  10. 注册域名需要资格吗_考教师资格证需要居住证吗?