详解JavaNIO Buffer类的属性和方法

阅读: 评论:0

详解JavaNIO Buffer类的属性和方法

详解JavaNIO Buffer类的属性和方法

前言

我们知道,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类,如有帮助,请点赞,谢谢!

本文发布于:2024-02-02 08:09:19,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170683256042489.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:详解   属性   方法   Buffer   JavaNIO
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23