详解JavaNIO Buffer类的属性和方法

2023-11-02

前言

我们知道,Java中的NIO实际上使用的是多种IO模型中的IO多路复用策略,在NIO中,引入了Buffer缓冲区Channel通道Selector选择器三个概念,现在先看一下Buffer缓冲区的一些基本知识。

介绍

NIO的Buffer本质上是一个内存块,既可以写入数据,也可以从中读取数据,Java NIO中代表缓冲区的Buffer类是一个抽象类,位于java.nio包中。
NIO的内部是一个内存块(数组),与普通的内存块(Java数组)不同的是,NIO Buffer对象提供了一系列有效地方法,用来进行写入和读取的交替访问。

在NIO中,有8种缓冲区类型,分别是 ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer,MappedByteBuffer。前7种Buffer类型覆盖了能在IO中传输的所有Java基本数据类型,第8种类型是一种专门用于内存映射的ByteBuffer类型,不同的Buffer子类可以操作的数据类型能够通过名称进行判断,比如IntBuffer只能操作Integer类型的对象。

属性

为了记录读写的状态和位置,Buffer类额外提供了一些重要的属性,其中有四个十分重要的成员属性capacitypositionlimitmark

capacity:容量

capacity属性表示Buffer内部容量的大小,一旦写入对象的数量超过了capacity,缓冲区满了,就不能再写入了。

capacity一旦初始化,就不能再改变,原因是Buffer类的对象在初始化的时候会按照capacity分配内部数组的内存,在数组内存被分配完毕后,就不能再改变大小了。

capacity并不是指内部内存块byte[]数组的字节数量,而是指能写入的数据对象的限制数量。

position:位置

position属性的值和缓冲区的读写模式有关,在不同的模式下,position属性值的含义是不同的,当缓冲区的读写模式发生改变时,position值会进行相应的调整。

写模式

  1. 在刚进入写模式时,position的值为0,表示当前写入的位置从0开始。
  2. 当一个数据写入缓冲区之后,position的位置会向后移动到下一个可写的位置。
  3. 初始position值为0,最大可写值为limit-1,当position的值达到limit时,表示缓冲区已经无位置可写了。

读模式

  1. 当缓冲区开始进入读模式时,position的值会被重置为0。
  2. 当从缓冲区开始读取数据的时候,也是从position位置开始读,读取数据后,position的位置会向后移动到下一个可读的位置。
  3. 在读模式下,limit表示可读数据的上限,position的最大值为最大可读上限limit,当position的位置达到limit,表示缓冲区已无数据可读。

Buffer的读写切换

当新建了一个缓冲区示例后,缓冲区默认处于写模式,在数据写入完毕之后,可以使用**flip()**方法将缓冲区切换为读模式。
在从写模式切换到读模式的过程中,position和limit的属性值会发生变化,limit的值设置为写模式时的position的值,表示可以读取的最大数据的位置,position由原来的写入位置变为新的可读位置,也就是0,表示可以从头开始读取。

limit:上限

limit属性表示可以写入或者读取的最大位置,具体含义也和读写的模式有关。

写模式

在写模式下,初始化时limit的值会被设置为缓冲区的capacity值,表示可以将缓冲区的容量写满。

读模式

在读模式下,limit的值被设置为写模式下的position的值,表示最多能从缓冲区中读取多少数据。

mark:标记

在缓冲区的操作过程中,可以将当前的position值临时存入mark属性中,在需要的时候,再从mark中取出暂存的标记值,恢复到position位置开始处理。

方法

allocate()

在使用Buffer实例之前,我们需要先获取Buffer子类的实例对象,并且分配内存空间,在获取实例对象时,并不是使用子类的构造器来创建,而是使用子类的allocate()方法。

在这里插入图片描述
在这里插入图片描述
从实例中可以看出,一个缓冲区在创建之后默认是处于写模式的,position的属性值为0,capacity和limit的属性值相同,都为20。

put()

在缓冲区创建完毕后,就可以写入对象,如果要把对象写入到缓冲区中,就需要调用put()方法,要求写入的数据类型和缓冲区的数据类型保持一致。

在这里插入图片描述
在这里插入图片描述
从结果可以看出,写入了5个元素之后,position的属性值就变为了5,指向了第6个可以写入的位置,而capacity和limit两个属性并没有发生变化。

flip()

在缓冲区写入完数据之后,还不能从中直接读取数据,需要将缓冲区切换为读模式,使用**flip()**翻转方法。

在这里插入图片描述

在这里插入图片描述
在翻转之后,position和limit属性的值都发生了变化,limit变为了写模式下position的值,表示最大的读取位置是5,而position的值变为0,表示从头开始读取。最后,清楚mark的值,因为mark储存的是写模式下的临时位置,发生翻转之后需要清空,防止发生混乱。

可以看一下源码:

在这里插入图片描述
那当数据读取完毕之后,如何从读模式切换到写模式呢,可以调用clear()方法清空或者调用compact()方法进行压缩。

get()

切换到读模式之后,就可以从缓冲区读取数据了,可以调用get()方法读取数据。并且缓冲区的属性也会相应的发生变化。
在这里插入图片描述
在这里插入图片描述
从以上实例可以看出,读操作会改变position的值,而不会改变limit的值,当position的值和limit的值相等时,表示所有数据读取完成,如果继续读取,则会抛出BufferUnderflowException异常。
在读取完毕之后是不能立即写入数据的,必需要调用clear()方法清空或者调用compact()方法进行压缩。
那么已经读取完的缓冲区是否可以重复读呢,答案是可以的,需要使用rewind()方法。

rewind()

rewind()也叫倒带,就像磁带一样,倒回去重新听一遍。

在这里插入图片描述
在这里插入图片描述
rewind()方法主要是调整了缓冲区的position和mark属性的值。
将position设置为0,limit保持不变,mark被清理,清除掉之前存储的位置。
在这里插入图片描述

mark()和reset()

这两个方法是配套使用的,mark()方法将当前position设置到mark属性中,reset()将mark属性的值恢复到position中,以便于从这个位置重复调用。

在这里插入图片描述
在这里插入图片描述
使用reset()方法之后,position的值为2,此时再去读取缓冲区,得到的结果为2,3,4。

clear()

在读模式下,调用clear()方法可以将缓冲区从读模式切换为写模式。
此时position的值被清零,limit的值变为capacity的值,可以一直写入,知道缓冲区满。

在这里插入图片描述
在这里插入图片描述

总结

  1. 使用子类对象的allocate()方法实例化Buffer对象。
  2. 使用put()方法添加数据。
  3. 当数据写入完毕后使用flip()方法,切换为读模式。
  4. 使用get()方法从缓冲区中读取数据。
  5. 读取完成之后,使用clear()或者compact()方法,将缓冲区从读模式切换为写模式。可以继续写入。

下篇文章总结一下Channel类,如有帮助,请点赞,谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解JavaNIO Buffer类的属性和方法 的相关文章

  • 使用 JPA/ORM 生成数据库模式是一个坏主意吗?

    Salve Part of 另一个问题 答案 https stackoverflow com questions 7595578关于 SO 以及其他声称相同的声明 如果您通过 JPA 更新数据库架构 但通常不是一个好的做法 您是否真的不应该
  • 光学标记阅读器的开源库[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我想要一个用于光学标记读取 OMR 的开源库 有这样的库吗 我想在我的 java 应用程序中使用这个库 zxing 可能对你有用 http
  • AbstractCollection 的 toArray 方法的实现中的代码有什么用

    public Object toArray Estimate size of array be prepared to see more or fewer elements Object r new Object size Iterator
  • 如何安装 C++ 的 VOCE?

    我正在尝试安装 VOCE api 它是为 C 和 Java 构建的语音识别 API 这是我第二次使用外部 C 库 也是第一次使用 Java C api 语音链接 http voce sourceforge net http voce sou
  • 在 Eclipse 中跨文件搜索注释掉的代码

    有没有一种快速方法可以在 Eclipse 中查找 Java 文件中所有注释掉的代码 也许是搜索中的任何选项 或者任何可以执行此操作的附加组件 它应该只能找到被注释掉的代码 而不是普通的注释 在 Eclipse 中 我只是在打开正则表达式复选
  • JPA 为每个项目选择最新实例

    假设我有一个会议实体 每次会议都有一个与会者和一个会议日期 在我的会议表中 我可能为每个与会者举行多个会议 每个会议都有不同的日期 我需要一个 JPA 查询 该查询将为所有与会者仅选择最新的会议 例如 如果我的桌子看起来像这样 Meetin
  • 如何使用 JAVA 和 ADB 命令检查 Appium 中键盘是否打开

    我正在尝试检查 Android 默认键盘是否打开 我没有找到任何可以在 Appium 中使用 JAVA 和 ADB 命令检查键盘的内容 我发现这个 ADB 命令可以检查键盘是否打开 adb shell dumpsys input metho
  • MAC OS 的 java.awt.Robot 类中出现无头环境错误

    我正在尝试使用 JavaFX 应用程序捕获屏幕截图Robot class 这是我在我的应用程序中使用的代码 Rectangle screenBounds new Rectangle Screen getPrimary getBounds g
  • Ubuntu 的打包 - Web 应用程序

    Web 应用程序没有与 C 或类似文件不同的 make 文件 但是 它需要放置在特定的目录中 例如 var www 我是 Linux 打包新手 所以我的问题是 如何将我的应用程序打包到 deb 中 以便在安装时将其放入 etc myprog
  • Apache HttpClient 执行时会在所有 HTTP 5XX 错误上抛出 IOException 吗?

    The Apache HttpClient 文档 http hc apache org httpcomponents client ga httpclient apidocs org apache http client HttpClien
  • jsf 中的类型未找到属性

    我正在尝试调用 jsf 中使用 primefaces 的属性 但我有错误 500 在托管bean PersonelBean 类型上找不到 我正在使用 hibernate jsf 和 spring PersonelBean java Mana
  • 在Java程序中计算zip文件的md5哈希值

    我有一个 zip 文件 在我的 Java 代码中我想计算 zip 文件的 md5 哈希值 有没有我可以用于此目的的 java 库 一些例子将非常感激 谢谢 几周前我通过这篇文章做到了这一点 http www javalobby org ja
  • 如何强制初始化 Hibernate JPA 代理以在 JSON 调用中使用它

    我有一个 Spring 3 JPA 2 0 应用程序 在我的 Controller我需要一个初始化的对象 但我有代理 我需要能够以编程方式初始化它 我需要类似的功能org hibernate Hibernate initialize Obj
  • Java 8 Stream - 为什么过滤器方法不执行? [复制]

    这个问题在这里已经有答案了 我正在学习使用java流进行过滤 但是过滤后的流没有打印任何内容 我认为过滤器方法没有被执行 我的过滤代码如下 Stream of d2 a2 b1 b3 c filter s gt s startsWith b
  • 如何映射 Map

    I tried ManyToMany cascade CascadeType ALL Map
  • Java中如何限制文件大小

    我正在我的应用程序中创建一个文件 并继续向该文件中写入一些内容 但是当我的文件达到一定大小 比如说 100 行 后 我想删除第一行并将新行写入底部 要求是我的文件应该受到限制 但它应该保留我写入文件的最新内容 请告诉我在Java中是否可行
  • Web服务连接超时和请求超时之间的区别

    WebClientTestService service new WebClientTestService int connectionTimeOutInMs 5000 Map
  • JTable中动态加载大量数据

    这是我的问题 我目前有一个 JTable 其中包含 5 000 到超过 200 000 行 你知道我要说什么了 数据已经加载到内存中了 这不是问题 但是如何 我可以创建一个高效的 JTable 以便它只加载以下行 是可见的 并且任何事件仅作
  • Web 应用程序似乎启动了名为 [22] 的线程,但未能停止它。这很可能造成内存泄漏

    我有一个 Web 应用程序 后端有 Servlet 部署在 tomcat 上 该应用程序是简单的java应用程序 我经常在服务器日志中看到此错误 严重 Web 应用程序似乎启动了一个名为 22 但未能阻止它 这很有可能 造成内存泄漏 是否存
  • 如何手动添加Android Studio依赖

    我多次尝试向我的项目添加依赖项 但每次都会出现错误 我想添加它们的依赖项是 de hdodenhof circleimageview 1 3 0 and com github bumptech glide glide 3 6 1 所以我想下

随机推荐

  • docker镜像与容器操作

    主要参考了docker从入门到实践 遇到自己不会的又补充了一些内容 一 镜像操作 1 获取镜像 docker pull 选项 Docker Registry 地址 端口号 仓库名 标签 Docker Registry 地址 lt 域名 IP
  • 樱花飘落,3D效果,抖音热门樱花飘落html

    樱花飘落 3D效果 抖音热门樱花飘落html 总结 代码如下 示例
  • [Android开发] 点击小图查看大图的功能、图片浏览器,聊天页面、朋友圈、微博、广场页面的查看大图功能,浏览大图功能,拖动关闭大图页面,完美的甚至完胜微信的过渡动画

    一 简介 属于你的侵入性低的大图查看器 完美的甚至完胜微信的过渡动画 同样支持视频 另外您可以自定义加载图片的内核 例如Glide Picasso或其他的 github地址 https github com FlyJingFish Open
  • Microsoft Minecraft产品线梳理

    目录 前言 1 Minecraft游戏本体 2 Minecraft Education Edition 3 Minecraft Marketplace 4 Minecraft Realms 5 Minecraft Dungeons
  • linux下线程使用

    什么是线程 线程 是进程内部的一个控制序列 即使不使用线程 进程内部也有一个执行线程 为什么要使用多线程 使用fork创建进程以执行新的任务 该方式的代价很高 多个进程间不会直接共享内存 线程是进程的基本执行单元 一个进程的所有任务都在线程
  • conda配置清华源

    conda配置清华源 问题描述 在Anaconda下准备下载东西的时候 出现了这样的报错或者出现下载速度极其慢 原因 因为默认下载东西的链接是国外的镜像 存在一些问题 因此将源改成国内的镜像即可 解决方案 1 使用清华的镜像链接 用清华镜像
  • Java 随机产生四位验证码

    import java util Random public class RandGenDemo public static void main String args 静态的方法不用new 直接对象 方法名 System out prin
  • linux 视频教程 韦山东,韦东山 linux 设备树详解

    简 介 设备树视频录制完毕 29节 现在只要69元 学员对此课程的评价 这是最翔实最实惠最精益求精的设备树教程 感兴趣的了解一下 以下是课程详情 设备树是什么 设备树是一种机制 用文本的方式描述硬件资源 我们写驱动前要先看原理图 确定硬件连
  • Listener

    观察者设计模式 它是事件驱动的一种体现形式 就好比在做什么事情的时候被人盯着 当对应做到某件事时 触发事件 观察者模式通常由以下三部分组成 1 事件源 触发事件的对象 2 事件 触发的动作 里面封装了事件源 3 监听器 当事件源触发事件时
  • postman本地测试接口的地址路径,如何获取和拼接

    首先 在本地进行接口自测 那么就是本地的ip 既 http localhost 其他就是其他的ip地址 接着是端口号以及所添加的共用路径 我们可以从springboot项目的配置文件application yml获取 找到 server 服
  • vue3中Cron表达式的使用

    效果
  • Python中多进程间通信(multiprocessing.Manager)

    Python中写多进程的程序 一般都使用multiprocesing模块 进程间通讯有多种方式 包括信号 管道 消息队列 信号量 共享内存 socket等 这里主要介绍使用multiprocessing Manager模块实现进程间共享数据
  • 爬虫的大概思路

    爬虫一般来说两种 一种是页面分析 分析页面获取整理出数据 毕竟是要展示数据在页面 获取这些从页面上 另一种是获取对应接口 通过API方式来获取 因为归根到底 都是前台后端交互发送请求响应请求 两种方式各有优劣 方式一应该是比较常见的 但是从
  • 断言简介说明

    转自 断言简介说明 下文笔者讲述断言简介说明 如下所示 断言简介 在Java中 assert关键字是从Java 4开始引入的 为了避免和老版本的Java代码中使用了assert关键字导致错误 Java在执行的时候默认是不启动断言检查的 这个
  • 后端代码审计——PHP数组

    文章目录 PHP数组 1 索引数组 2 关联数组 3 数组创建 3 1 直接赋值 3 2 array 语言结构 4 多维数组 4 1 创建多维数组 5 数组元素访问 5 1 组元素操作 5 2 元素操作 5 3 数组的遍历 5 4 for
  • win11 安装 Anaconda(2022.10)+pycharm(2022.3/2023.1.4)+配置虚拟环境

    目录 一 安装Anaconda 二 Anaconda配置环境变量 三 Anaconda更改虚拟环境安装路径 创建虚拟环境 四 安装pycharm 五 pycharm配置Anaconda环境 一 安装Anaconda 1 下载 官网慢 可以选
  • app渗透-外在信息收集

    app渗透 外在信息收集 5 外在信息收集 5 1外在抓包 frida r0capture 5 1 1 frida的安装和使用 1 安装 2 使用测试 5 2 1 r0capture使用 5 外在信息收集 5 1外在抓包 frida r0c
  • 问题 D: 数据结构练习 -- 栈的操作

    题目描述 对输入整数序列1 2 3 执行一组栈操作 输出操作的出栈序列 输入 每行是一个测试用例 表示一个操作序列 操作序列由P和Q两个符号组成 P表示入栈 Q表示出栈 每个操作序列长度不超过1000 输出 对每个操作序列 输出出栈序列 若
  • MySQL——数据的增删改

    2023 9 12 本章开始学习DML 数据操纵语言 语言 相关学习笔记如下 DML语言 数据操作语言 插入 insert 修改 update 删除 delete 一 插入语句 方式一 经典的插入 语法 insert into 表名 列名
  • 详解JavaNIO Buffer类的属性和方法

    前言 我们知道 Java中的NIO实际上使用的是多种IO模型中的IO多路复用策略 在NIO中 引入了Buffer缓冲区 Channel通道 Selector选择器三个概念 现在先看一下Buffer缓冲区的一些基本知识 介绍 NIO的Buff