Java NIO (二)NIO Buffer类的重要方法

news/2024/2/29 15:48:13/文章来源:https://blog.csdn.net/geminigoth/article/details/135585848

1 allocate()方法

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

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("afer allocate ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

abb55b6d2a6b40129c5a704d62e6c1a6.png

        本例中,IntBuffer是具体的Buffer子类,通过调用IntBuffer.allocate(20)创建了一个intBuffer实例对象,并且分配了20*4字节的内存空间。运行程序后,通过输出结果,可以查看一个新建缓冲区实例对象的主要属性值。

        从上面的运行结果可以看出:一个缓冲区在新建后处于写模式,position属性(代表写入位置)的值是0,缓冲区的capacity值是初始化时allocate方法的参数值,而limit最大可写上限值也为allocate方法的初始化参数值。

2 put()方法

        在调用allocate方法分配内存、返回了实例对象后,缓冲区实例对象处于写模式,可以写入对象,如果要把对象写入缓冲区,就需要调用put()方法。put方法很简单,只有一个参数,即需要写入的独享,只不过要求写入的数据类型与缓冲区的类型保持一致。接着上面的例子向刚刚创建的intBuffer缓存实例对象写入5个整数。

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("before put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {intBuffer.put(i);}System.out.println("after put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

 0b3efdefc9dc44c6bef3293dda479834.png

        从结果可以看到,写入了5个元素后,缓冲区的position属性值变成了5,所以指向了第6个(从0开始)可以进行写入的元素位置。limit、capacity两个属性的值没有发生变化。

3 flip()方法 

        向缓冲区写入数据之后,是否可以直接从缓冲区读取数据呢?答案是否定的。这时缓冲区还处于写模式,如果需要读取数据,要将缓冲区转换成读模式。flip()翻转方法是Buffer类提供的一个模式转变的重要方法,作用是将写模式转换成读模式。接着前面的例子演示flip()方法。

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("before put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {intBuffer.put(i);}System.out.println("after put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.flip();System.out.println("after flip ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

063045aa1b1f4fb5adc918b8cb4d615b.png

        调用flip方法后,新模式可读上限limit的值变成了之前写模式下的position的值,也就是5;而新模式下的position的值变成了0,表示从头开始读取。

        对flip()方法从写入到读取转换的规则,再一次详细介绍:

        首先,设置可读上限limit的属性值。将写模式下的缓冲区中内容的最后写入位置position的值作为读模式下的limit上限值。

        其次,把读的起始位置position的值设为0,表示从头开始读。

        最后,清除之前的mark标记,因为mark保存的是写模式下的临时位置,发生模式转换后,如果继续使用旧的mark标记,就会造成位置混乱。

        上面三步可以查看Buffer.flip()方法的源码,具体如下:

 public Buffer flip() {//设置可读上限limit,设置为写模式下的position值limit = position;//把读的起始位置position的值设为0,表示从头开始读position = 0;//清除之前的mark标记mark = -1;return this;}

         新的问题来了:在读取完后,如果再一次将缓冲区切换成写模式呢?答案是:可以调用Buffer.clear()清空或者Buffer.compact()压缩方法,它们可以将缓冲区切换为写模式。

4 get()方法

        调用flip()方法将缓冲区切换成读模式后,就可以开始从缓冲区读取数据了。读取数据的方法很简单,可以调用get()方法从position的位置读取一个数据,并且进行相应的缓冲区属性的调整。接着前面调用flip()方法的实例,演示缓冲区的读取操作。

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("before put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {intBuffer.put(i);}System.out.println("after put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.flip();System.out.println("after flip ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//先读取两个数据for (int i = 0; i < 2; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第一次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//再读取三个数据for (int i = 0; i < 3; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第二次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

c57f39d84aa14eea94d220c9c75b6cfd.png

        从输出看到,读取操作会改变可读位置position的值,而可读上限limit的值不会改变。在position值和limit值相等时,表示所有数据读取完成,position指向了一个没有数据的元素位置,已经不能在读了。这里强调一下,在读完之后是否可以立即对缓冲区进行数据写入呢?答案是不能。现在还处于读模式,必须调用clear()或compact()方法,即清空或压缩缓冲区,将缓冲区切换成写模式。

5 rewind()方法

        已经读完的数据,如果需要再读一遍,可以调用rewind()方法。rewind()方法也叫倒带,就像播放磁带一样,再重新播放。接着前面的代码,继续rewind()方法使用的演示。

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("before put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {intBuffer.put(i);}System.out.println("after put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.flip();System.out.println("after flip ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//先读取两个数据for (int i = 0; i < 2; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第一次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//再读取三个数据for (int i = 0; i < 3; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第二次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.rewind();System.out.println("after rewind -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

 97370672218841e49c21601bc1293b3c.png

        rewind()方法主要是调整了缓冲区的position属性与mark属性,调整规则如下:

        1、position重置为0,所以可以重读缓冲区的所有数据。

        2、limit保持不变,数据量还是一样的,仍然可以从缓冲区读取的元素数量。

        3、mark被清理,表示之前的临时位置不能再用了。

        rewind()源码如下:

public Buffer rewind() {//重置为0,所以可以重读缓冲区中的所有数据position = 0;//mark被清理,表示之前的临时位置不能再用了mark = -1;return this;}

         通过源码可以看到rewind()和flip()方法很像,区别在于:rewind()方法不会影响limit属性值;而flip()方法会重设limit属性值。

6 mark()和reset()方法

        mark()和reset()方法是配套使用的:mark()方法将当前position的值保存起来放在mark属性中,让mark属性记住这个临时位置;然后可以调用reset()方法将mark的值恢复到position中。

        例如,在前面重复读取的示例代码中,在读到第三个元素(i=2时)时,可以调用mark方法,把当前位置position的值保存到mark属性中,这时mark属性值是2。

        接下来可以调用reset()方法,将mark属性的值恢复到position中,这样就可以从位置2(第三个元素)开始重复读取了。

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("before put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {intBuffer.put(i);}System.out.println("after put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.flip();System.out.println("after flip ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//先读取两个数据for (int i = 0; i < 2; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第一次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//再读取三个数据for (int i = 0; i < 3; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第二次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.rewind();System.out.println("after rewind -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {if(i == 2){intBuffer.mark();}int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after mark -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.reset();for (int i = 2; i < 5; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after reset -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

6552eeffaf6e40aa8448321af65aa0c3.png

        在上面的代码中,首先调用reset方法把mark中的值恢复到position中,因此读取的位置position就是2,表示可以再次开始从第三个元素开始读取数据。调用reset方法后,position的值是2,此时去读取缓冲区,输出后面的三个元素2 、3 、4。

7 clear()方法

        在读模式下,调用clear方法将缓冲区切换成写模式。此方法的作用是:

        (1)将position清零。

        (2)limit设置为capacity最大容量值,可以一直写入,直到缓冲区写满。

        接着上面的示例,调用clear方法。

        

public class AllocateTest {static IntBuffer intBuffer = null;//一个整型的Buffer静态变量public static void main(String[] args) {//创建一个intbuffer 实例对象intBuffer = IntBuffer.allocate(20);System.out.println("before put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {intBuffer.put(i);}System.out.println("after put ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.flip();System.out.println("after flip ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//先读取两个数据for (int i = 0; i < 2; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第一次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());//再读取三个数据for (int i = 0; i < 3; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after get 第二次 ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.rewind();System.out.println("after rewind -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());for (int i = 0; i < 5; i++) {if(i == 2){intBuffer.mark();}int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after mark -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.reset();for (int i = 2; i < 5; i++) {int j = intBuffer.get();System.out.println("j = " + j);}System.out.println("after reset -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());intBuffer.clear();System.out.println("after clear -- ----------------");System.out.println("position = " + intBuffer.position());System.out.println("limit = " + intBuffer.limit());System.out.println("capacity = " + intBuffer.capacity());}
}

 d8545bda124b42bb8d9e78b8600fdd44.png

        在缓冲区处于读模式时,调用clear方法,缓冲区被切换成写模式,可以看到清空了position的值,值被设置为0, 并且limit值为最大容量。

8 使用Buffer类的基本步骤

        总体来说,使用Java NIO Buffer类的基本步骤如下:

        (1)使用创建子类实例对象的allocate()方法创建一个Buffer类的实例对象。

        (2)调用put()方法将数据写入缓冲区。

        (3)写入完成后,再开始读取数据之前调用flip()方法,将缓冲区切换成读模式。

        (4)调用get()方法,可以从缓冲区读取数据。

        (5)读取完成后,调用clear()或compact()方法,将缓冲区从读模式切换成写模式,可以继续写入数据。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_925717.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、Sharding-JDBC系列04:分库分表后,如何不停机迁移数据?

目录 停机迁移方案 双写迁移方案 一般会有两种方案&#xff1a; 停机迁移方案 这种方案最简单也是最low的。 数据迁移前&#xff0c;在网站或者app挂个公告&#xff0c;说0点到早上6点系统进行维护&#xff0c;无法访问。 接着到0点停机&#xff0c;系统停掉&#xff0c;…

k8s---配置资源管理

目录 配置资源管理的方式 secret pod如何来引用secret&#xff1f;&#xff1f;&#xff1f; 陈述式创建&#xff1a; 声明式创建 Secret创建加密文件 使用token挂载 环境变量使用 docker-registry ConfigMap 陈述式 热更新 总结&#xff1a; 配置资源管理的方式 …

Go-gin-example 第二部分 jwt验证

文章目录 使用 JWT 进行身份校验jwt知识点补充认识JWTTOKEN是什么jwt的使用场景jwt的组成headerpayloadsignature 下载依赖包编写 jwt 工具包jwt中间件编写如何获取token 编写获取token的Apimodels逻辑编写路由逻辑编写修改路由逻辑 验证token将中间件接入Gin功能验证模块 续接…

【开源】基于JAVA语言的固始鹅块销售系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固始鹅块模块2.4 鹅块订单模块2.5 评论管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 鹅块类型表3.2.2 鹅块表3.2.3 鹅块订单表3.2.4 鹅块评论表 四、系统展示五、核心代码5.…

FPGA之初探

FPGA的构成 基本逻辑单元CLB CLB是FPGA的基本逻辑单元&#xff0c; 一个 CLB 包括了 2 个 Slices&#xff0c;所以知道Slices的数量就可以知道FPGA的“大概”逻辑资源容量了。一个 Slice 等于 4 个6输入LUT8个触发器(flip-flop)算数运算逻辑&#xff0c;每个 Slice 的 4 个触发…

[足式机器人]Part2 Dr. CAN学习笔记-Advanced控制理论 Ch04-17 串讲

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Advanced控制理论 Ch04-17 串讲

Komodor:Kubernetes 监控工具全面指南

为了方便起见&#xff0c;Komodor 提供了一个简单的 Web 界面&#xff0c;以帮助您监控 Kubernetes 集群的状态。它拥有付费和免费增值计划&#xff0c;除了在出现问题时通知用户外&#xff0c;还拥有一系列方便的工具&#xff0c;用于跟踪和管理集群中部署的资源的状态。让我们…

如何用GPT进行论文润色与改写?

详情点击链接&#xff1a;如何用GPT进行论文润色与改写&#xff1f; 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Claude2二定…

逻辑回归(解决分类问题)

定义&#xff1a;逻辑回归是一种用于解决分类问题的统计学习方法。它通过对数据进行建模&#xff0c;预测一个事件发生的概率。逻辑回归通常用于二元分类问题&#xff0c;即将数据分为两个类别。它基于线性回归模型&#xff0c;但使用了逻辑函数&#xff08;也称为S形函数&…

MR-GCN

∘ Φ \circ_Φ ∘Φ​ denotes a convolution Let b l o c k d i a g blockdiag blockdiag(A) be a n1n3-by-n2n3 block diagonal matrix&#xff0c; f o l d fold fold indicate its inverse operator diagonal degree tensor D \mathcal{D} D 作者未提供代码

【学习心得】Git深入学习

若您还未安装Git或是只想简单使用&#xff0c;可以先看看我的文章“Git快速上手”【学习心得】Git快速上手http://t.csdnimg.cn/gsaGj 一、深入学习Git必须熟悉两个概念 &#xff08;1&#xff09;【四个区】Git本地有三个区&#xff0c;远程仓库也可以看出成一个区域 工作区…

vtk9.3 + Visual Studio2019 + Cmake3.28 win11 上的环境安装(这个过程网上比较多,自己记录下过程加深下印象)

开始 介绍 欢迎来到 VTK&#xff01;我们建议您首先阅读《VTK book》&#xff0c;这是一本全面的 VTK 指南&#xff0c;涵盖了其功能的所有方面。此外&#xff0c;您可能会发现探索 VTK 示例很有帮助&#xff0c;这是一组有用的参考资料&#xff0c;演示了如何使用 VTK 的不同模…

ASP.NET Core 的 Web Api 实现限流 中间件

Microsoft.AspNetCore.RateLimiting 中间件提供速率限制&#xff08;限流&#xff09;中间件。 它是.NET 7 以上版本才支持的中间件&#xff0c;刚看了一下&#xff0c;确实挺好用&#xff0c;下面给大家简单介绍一下&#xff1a; RateLimiterOptionsExtensions 类提供下列用…

Elasticsearch 7.8.0从入门到精通

安装Elasticsearch 7.8.0 官网&#xff1a;Elasticsearch 7.8.0 | Elastic 大家下载所需要的安装包即可。然后解压缩&#xff1a; Elasticsearch是通过java编写的&#xff0c;所以自带jdk。多好&#xff0c;下载Elasticsearch赠送jdk 0.0&#xff0c;不过一般我们用自己的jdk…

利用Lambda表达式实现vector中pair/结构体的排序

众所周知&#xff0c;对于vector<pair<int, int> >若直接使用sort排序&#xff0c;会默认按照pair的第一个关键字从小到大进行排序&#xff1a; #include <bits/stdc.h>using namespace std;int main() {vector<pair<int, int> > p;p.push_back…

select子句简单查询

Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 目录 数据查询 起别名 连接 ​编辑 去重 ​编辑 另外补充几个不常用的命令 如果要进行查询,那么需要使用数据操纵语言&#xff08;Data Manipulation Language&#xff0c;DML&am…

EChars

1.引入 Apache ECharts <!DOCTYPE html> <html><head><meta charset"utf-8" /><!-- 引入刚刚下载的 ECharts 文件 --><script src"echarts.js"></script></head> </html> 2. <!-- 为 ECharts 准…

[自动驾驶算法][从0开始轨迹预测]:二、自动驾驶系统中常用的坐标系及相应的转换关系

自动驾驶中常见的坐标系与坐标转换 1. 传感器坐标系1.1 相机坐标系统1) 相机相关基础知识2) 相机各坐标系图像/像素坐标系相机坐标系像平面坐标系 3) 相机各坐标系之间的转换像平面坐标系到像素坐标系的转换&#xff08;平移缩放变换&#xff09;相机坐标系转像平面坐标系&…

tcpdump常用参数以及wireshark密文解密

tcpdump常用参数以及wireshark密文解密 文章目录 一、tcpdump命令和常用参数二、在wireshark中协议解析 tcpdump常用参数 一、tcpdump命令和常用参数 tcpdump常用命令&#xff1a;tcpdump -i eth0 src host 11.6.224.1 and udp port 161 -s 0 -w 161.pcap &#xff08;161为sn…

自学Python,需要注意哪些?

为什么要学习Python&#xff1f; 在学习Python之前&#xff0c;你不要担心自己没基础或“脑子笨”&#xff0c;我始终认为&#xff0c;只要你想学并为之努力&#xff0c;就能学好&#xff0c;就能用Python去做很多事情。在这个喧嚣的时代&#xff0c;很多技术或概念会不断兴起…