NIO Buffer类的重要方法

news/2024/4/24 11:16:43/文章来源:https://blog.csdn.net/yitian881112/article/details/127624201

1 allocate()创建缓冲区

在使用Buffer(缓冲区)之前,我们首先需要获取Buffer子类的实例对象,并且分配内存空间。为了获取一个Buffer实例对象,这里并不是使用子类的构造器new来创建一个实例对象,而是调用子类的allocate()方法。下面的程序片段就是用来获取一个整型Buffer类的缓冲区实例对象,代码如下:

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;public static void allocatTest(){//调用allocate方法,而不是使用newintBuffer = IntBuffer.allocate(30);//输出buffer的主要属性值Logger.info("------------after allocate------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...allocatTest |>  ------------after allocate------------------allocatTest |>  position=0allocatTest |>  limit=20allocatTest |>  capacity=20}

例子中,IntBuffer是具体的Buffer子类,通过调用IntBuffer.allocate(30),创建了一个Intbuffer实例对象,并且分配了30 * 4个字节的内存空间。

一个缓冲区在新建后,处于写入的模式,position写入位置为0,最大可写上限limit为的初始化值(这里是20),而缓冲区的容量capacity也是初始化值。

2 put()写入到缓冲区

在调用allocate方法分配内存、返回了实例对象后,缓冲区实例对象处于写模式,可以写入对象。要写入缓冲区,需要调用put方法。put方法很简单,只有一个参数,即为所需要写入的对象。不过,写入的数据类型要求与缓冲区的类型保持一致。

接着前面的例子,向刚刚创建的intBuffer缓存实例对象中,写入的5个整数,代码如下:

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;//省略了创建缓冲区的代码,具体看源代码工程public static void putTest(){for (int i = 0; i< 5; i++){//写入一个整数到缓冲区intBuffer.put(i);}//输出缓冲区的主要属性值Logger.info("------------after put------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...putTest |>  ------------after putTest------------------putTest |>  position=5putTest |>  limit=20putTest |>  capacity=20}

从结果可以看到,position变成了5,指向了第6个可以写入的元素位置。而limit最大写入元素的上限、capacity最大容量的值,并没有发生变化。

3 flip()翻转
向缓冲区写入数据之后,是否可以直接从缓冲区中读取数据呢?

呵呵,不能。这时缓冲区还处于写模式,如果需要读取数据,还需要将缓冲区转换成读模式。flip()翻转方法是Buffer类提供的一个模式转变的重要方法,它的作用就是将写入模式翻转成读取模式。

接着前面的例子,演示一下flip()方法的使用:

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;//省略了缓冲区的创建、写入的代码,具体看源代码工程public static void flipTest(){//翻转缓冲区,从写模式翻转成读模式intBuffer.flip();//输出缓冲区的主要属性值Logger.info("------------after flip ------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...flipTest |>  ------------after flipTest ------------------flipTest |>  position=0flipTest |>  limit=5flipTest |>  capacity=20}

调用flip方法后,之前写入模式下的position值5,变成了可读上限limit值5;

而新的读取模式下的position值,简单粗暴地变成了0,表示从头开始读取。对flip()方法的从写入到读取转换的规则,

详细的介绍如下:

  • 首先,设置可读的长度上限limit。将写模式下的缓冲区中内容的最后写入位置position值,作为读模式下的limit上限值。
  • 其次,把读的起始位置position的值设为0,表示从头开始读。
  • 最后,清除之前的mark标记,因为mark保存的是写模式下的临时位置。在读模式下,如果继续使用旧的mark标记,会造成位置混乱。

有关上面的三步,其实可以查看flip方法的源代码,Buffer.flip()方法的源代码如下:

        public final Buffer flip() {limit = position;  //设置可读的长度上限limit,为写入的positionposition = 0;       //把读的起始位置position的值设为0,表示从头开始读mark = UNSET_MARK;  // 清除之前的mark标记return this;}

至此,大家都知道了,如何将缓冲区切换成读取模式。新的问题来了,在读取完成后,如何再一次将缓冲区切换成写入模式呢?可以调用Buffer.clear()清空或者Buffer.compact()压缩方法,它们可以将缓冲区转换为写模式。

Buffer的模式转换,大致如图3-1所示。
在这里插入图片描述
4 get()从缓冲区读取

调用flip方法,将缓冲区切换成读取模式。这时,可以开始从缓冲区中进行数据读取了。读数据很简单,调用get方法,每次从position的位置读取一个数据,并且进行相应的缓冲区属性的调整。

接着前面flip的使用实例,演示一下缓冲区的读取操作,代码如下:

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;//省略了缓冲区的创建、写入、翻转的代码,具体看源代码工程public static void getTest(){//先读2个for (int i = 0; i< 2; i++){int j = intBuffer.get();Logger.info("j = " + j);}//输出缓冲区的主要属性值Logger.info("------------after get 2 int ------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());//再读3个for (int i = 0; i< 3; i++){int j = intBuffer.get();Logger.info("j = " + j);}//输出缓冲区的主要属性值Logger.info("------------after get 3 int ------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...}

输出结果

        getTest |>  ------------after get 2 int ------------------getTest |>  position=2getTest |>  limit=5getTest |>  capacity=20getTest |>  ------------after get 3 int ------------------getTest |>  position=5getTest |>  limit=5getTest |>  capacity=20

从程序的输出结果,我们可以看到,读取操作会改变可读位置position的值,而limit值不会改变。如果position值和limit的值相等,表示所有数据读取完成,position指向了一个没有数据的元素位置,已经不能再读了。此时再读,会抛出BufferUnderflowException异常。这里强调一下,在读完之后,是否可以立即进行写入模式呢?不能。现在还处于读取模式,我们必须调用Buffer.clear()或Buffer.compact(),即清空或者压缩缓冲区,才能变成写入模式,让其重新可写。另外,还有一个问题:缓冲区是不是可以重复读呢?答案是可以的。

5 rewind()倒带

已经读完的数据,如果需要再读一遍,可以调用rewind()方法。rewind()也叫倒带,就像播放磁带一样倒回去,再重新播放。

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;//省略了缓冲区的创建、写入、读取的代码,具体看源代码工程public static void rewindTest() {//倒带intBuffer.rewind();//输出缓冲区属性Logger.info("------------after rewind ------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...}

这个范例程序的执行结果如下:

        rewindTest |>  ------------after rewind ------------------rewindTest |>  position=0rewindTest |>  limit=5rewindTest |>  capacity=20

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

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

(2)limit保持不变,数据量还是一样的,仍然表示能从缓冲区中读取多少个元素。

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

Buffer.rewind()方法的源代码如下:

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

通过源代码,我们可以看到rewind()方法与flip()很相似,区别在于:rewind()不会影响limit属性值;而flip()会重设limit属性值。在rewind倒带之后,就可以再一次读取,重复读取的示例代码如下:

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;//省略了缓冲区的读取、倒带的代码,具体看源代码工程public static void reRead() {for (int i = 0; i< 5; i++) {if (i == 2) {//临时保存,标记一下第3个位置intBuffer.mark();}//读取元素int j = intBuffer.get();Logger.info("j = " + j);}//输出缓冲区的属性值Logger.info("------------after reRead------------------");Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...}

这段代码,和前面的读取示例代码基本相同,只是增加了一个mark调用。

6 mark( )和reset( )

Buffer.mark()方法的作用是将当前position的值保存起来,放在mark属性中,让mark属性记住这个临时位置;之后,可以调用Buffer.reset()方法将mark的值恢复到position中。也就是说,Buffer.mark()和Buffer.reset()方法是配套使用的。两种方法都需要内部mark属性的支持

7 clear( )清空缓冲区

在读取模式下,调用clear()方法将缓冲区切换为写入模式。此方法会将position清零,limit设置为capacity最大容量值,可以一直写入,直到缓冲区写满。

接着上面的实例,演示一下clear方法。代码如下:

        package com.crazymakercircle.bufferDemo;//...public class UseBuffer{static IntBufferintBuffer = null;//省略了之前的buffer操作代码,具体看源代码工程public static void clearDemo() {Logger.info("------------after clear------------------");//清空缓冲区,进入写入模式intBuffer.clear();//输出缓冲区的属性值Logger.info("position=" + intBuffer.position());Logger.info("limit=" + intBuffer.limit());Logger.info("capacity=" + intBuffer.capacity());}//...}

这个程序运行之后,结果如下:

        main |>清空clearDemo |>  ------------after clear------------------clearDemo |>  position=0clearDemo |>  limit=20clearDemo |>  capacity=20

在缓冲区处于读取模式时,调用clear(),缓冲区会被切换成写入模式。调用clear()之后,我们可以看到清空了position的值,即设置写入的起始位置为0,并且写入的上限为最大容量。

8 使用Buffer类的基本步骤

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

(1)使用创建子类实例对象的allocate()方法,创建一个Buffer类的实例对象。
(2)调用put方法,将数据写入到缓冲区中。
(3)写入完成后,在开始读取数据前,调用Buffer.flip()方法,将缓冲区转换为读模式。(4)调用get方法,从缓冲区中读取数据。
(5)读取完成后,调用Buffer.clear() 或Buffer.compact()方法,将缓冲区转换为写入模式。

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

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

相关文章

带你走入C++动态多态的底层

多态按字面的意思就是多种形态&#xff0c;相同的方法调用&#xff0c;但是有不同的实现方式。多态性可以简单地概括为“一个接口&#xff0c;多种方法&#xff0c;实现接口与实现的分离。 C有两种多态形式&#xff1a; 静态多态动态多态而本文主要介绍动态多态的应用。 动态…

力扣1662(javapython)-检查两个字符串数组是否相等(简单)

题目: 给你两个字符串数组 word1 和 word2 。如果两个数组表示的字符串相同,返回 true ;否则,返回 false 。 数组表示的字符串 是由数组中的所有元素 按顺序 连接形成的字符串。示例 1: 输入:word1 = ["ab", "c"], word2 = ["a", "bc…

SpringBoot:ssm和springboot整合

目录 一、整合Mybatis 因为要使用逆向生成代码 pom.xml generatorConfig.xml application.yml 测试 BookController SpringbootmybatisApplication jdbc.properties 二、整合mybatisplus 简介 application.yml MPGenerator SpringbootmpApplication 三、使用my…

ensp华为配置NAT

ensp华为配置NAT 文章目录ensp华为配置NAT1 对PC进行地址、掩码及网关配置2 对路由器进行初始配置3 ART配置3.1 静态NAT配置3.2 动态NAT配置3.3 端口NAT (NAPT) 的配置3.4 Easy IP的配置3.5 NAT Server的配置4 总结拓扑图如图&#xff1a;1 对PC进行地址、掩码及网关配置 略 …

计算机毕设(附源码)JAVA-SSM佳音大学志愿填报系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

计算机毕设(附源码)JAVA-SSM蓟县农家乐网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

通俗易懂!一文看懂手机Root的操作与防护

Root&#xff0c;对于任何手机发烧友、玩机客、从事移动设备研发的人员来说&#xff0c;并不陌生&#xff0c;它代表绝大部分移动设备的使用者能够掌握到的最高权限。 从技术层次来讲&#xff0c;用户拥有了修改系统文件的权限&#xff0c;甚至可以控制账户、增加或删除硬件等…

java毕业设计——基于java+JSP+sqlserver的智能在线考试信息管理系统设计与实现(毕业论文+程序源码)——智能在线考试信息管理系统

基于javaJSPsqlserver的智能在线考试信息管理系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于javaJSPsqlserver的智能在线考试信息管理系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。 文章目录&a…

内部财务经营分析该怎么做?

对于日常在企业工作的财务人员来说&#xff0c;做对外财务报表分析的机会并不多&#xff0c;我们在网上经常看到的对上市公司财务报表的分析&#xff0c;是基于投资人的角度来对这家公司披露的财务及经营信息所做的分析。 实际工作当中&#xff0c;大家应用到更多的其实是内部…

【Linux详解】——gcc/g++/gdb/git的使用

&#x1f4d6; 前言&#xff1a;本期将学习gcc/g/gdb/git的使用 目录&#x1f552; 1. 程序的翻译过程&#x1f552; 2. 理解选项的含义&#x1f552; 3. 动态链接和静态链接&#x1f552; 4. Linux项目自动化构建工具-make/Makefile&#x1f558; 4.1 背景&#x1f558; 4.2 使…

发布四大战略举措,亚马逊云科技看准了中国云市场的哪些新机会?

导读&#xff1a;全球最大的云厂商&#xff0c;在中国的最新布局。 2022年10月13日&#xff0c;亚马逊云科技在线上举办2022中国峰会。亚马逊云科技不仅发布了云计算技术趋势展望&#xff0c;还宣布了深耕中国市场的四大战略举措&#xff1a;“连中外、襄百业、携伙伴、促绿色”…

【Java8新特性】函数式接口

目录1. 介绍1.1 FunctionInterface注解1.2 函数式接口的调用2. 函数式编程2.1 Lambda的延迟加载技术2.2 Lambda表达式的使用3. 常用的函数式接口3.1 Supplier生产型接口3.2 Consumer消费型接口默认方法&#xff1a;andThen3.3 Predicate条件判断接口3.4 Function普通函数接口默…

ASP.NET Core教程-跨域配置(CORS Configuration)

更新记录 转载请注明出处: 2022年11月1日 发布。 2022年11月1日 从笔记迁移到博客。说明 Cross-Origin Resource Sharing,跨域资源共享 配置方式 在ASP.NET Core中有2种方式配置跨越,中间件方式(middleware approach) 和 特性修饰方式(attributes approach)。 中间件方式…

在Jupyter Notebook中使用Matplotlib(Anaconda3)

Matplotlib&#xff08;官网 Matplotlib — Visualization with Python &#xff09;是一个用于创建二维图形的Python库&#xff0c;它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形。将Jupyter Notebook于Matplotlib结合使用效果更好。 在Anaconda3的Jupyter …

HCL AppScan Standard漏洞扫描处理记录

官网&#xff0c;标准版应该是免费的&#xff0c;下载了标准版&#xff0c;没提示激活啥的&#xff0c;最近处理客户的漏洞扫描问题&#xff0c;主要就是修改nginx配置&#xff0c;各种查资料&#xff0c;不停的扫描验证&#xff0c;简单记录下吧。 APP简单使用 app快速下载地…

flutter 系列之:flutter 中的幽灵offstage

文章目录简介Offstage详解Offstage的使用总结简介 我们在使用flutter的过程中&#xff0c;有时候需要控制某些组件是否展示&#xff0c;一种方法是将这个组件从render tree中删除&#xff0c;这样这个组件就相当于没有出现一样&#xff0c;但是有时候&#xff0c;我们只是不想…

技术革新,取代传统会议模式?原来这么简单

随着AI人工智能的盛行&#xff0c;各领域面临前所未有的技术革新。人脸识别作为人工智能的一项重要技术&#xff0c;为工作及生活带来极大便捷&#xff0c;增效赋能。 人脸签到技术5大优势 01.人脸识别稳定&#xff0c;即使在光源不佳、角度受限的环境下也能精准识别&#xff1…

Libuv 各个回调(异步)事件的调用时机

Libuv 各个回调&#xff08;异步&#xff09;事件的调用时机 uv_close、uv_timer_start uv_close中注册的回调事件&#xff08;close_cb&#xff09;查阅官网API文档&#xff0c;Handle句柄是调用uv_close便会立即关闭&#xff0c;而注册的回调事件将推迟到下一次Loop循环中执…

设计模式——创建型模式

五大-创建型模式一、单例模式1、简介2、单例模式八种方式2.1、饿汉式&#xff08;静态常量&#xff09;2.2、饿汉式&#xff08;静态代码块&#xff09;2.3、懒汉式&#xff08;线程不安全&#xff09;2.4、懒汉式&#xff08;线程安全&#xff0c;加同步方法&#xff09;2.5、…

C2 实验 学习笔记

C2 实验 免责声明 本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关. C2隐藏技术 CDN 准备 一台 vultr centos7 机器一个域名cloudflare 账号 挂上 cdn 在域名购买后配置&#xff0c;cf 中的域名解析&#xff0c;在 cf 中配置…