学科分类
目录
Java基础

Buffer(缓冲器)

Java NIO中的Buffer用于和NIO中的Channel进行交互,交互时数据会从Channel读取到Buffer中,或从Buffer写入到Channel中,如图1所示。

图1 Buffer和Channel

从结构上来说,Buffer类似于一个数组,它可以保存多个类型相同的数据。从类型上来说,Buffer是一个抽象类,其子类有ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer,这些子类中最常用的是ByteBuffer和CharBuffer,其他则使用较少。

Buffer类的子类中并没有提供构造方法,因此不能通过构造方法来创建对象。要想创建Buffer对象,通常会通过子类中的static XxxBuffer allocate(int capacity)方法来实现,其中Xxx表示不同的数据类型,而capacity表示容量,此方法的含义是创建一个容量为capacity的XxxBuffer对象。例如创建一个容量为6的CharBuffer对象的语句如下:

CharBuffer buffer = CharBuffer.allocate(6);

在学习Buffer的使用之前,需要对Buffer中的三个重要概念有所理解,这三个概念分别是capacity(容量)、limit(界限)和position(位置),其含义如下:

● capacity(容量):缓冲区的容量表示该Buffer的最大数据容量,即最多可以存储多少数据。缓冲区的容量值不能为负数,也不能够改变。

● limit(界限):表示Buffer容器中不可被读取的区域的第一个索引,即位于Buffer容器中索引为0到limit之间的区域都可以进行读取操作。缓冲区的limit值从不为负,也从不大于其容量。

● position(位置):用于指定下一个可以被读写的缓冲区位置索引。新创建的Buffer对象,position的默认值为0,每进行一次读取或写入操作,position的值都会自动向后移动一步。如果向Buffer缓冲区中执行8次写入操作,那么position的值为8,即指向Buffer中的第9个元素的索引位置。

在Buffer类中,定义了很多方法,其常见方法如表1所示。

表1 Buffer类的常用方法

方法声明 功能描述
int capacity() 获取缓冲区的大小
Buffer clear() 清除缓冲区,将position设置为0,limit设置为capacity
Buffer flip() 反转缓冲区,先将limit设置为当前position位置,然后再将position设置为0
boolean hasRemaining() 判断当前位置(position)和界限(limit)之间是否还有元素
int limit 获取Buffer的limit位置
Buffer limit(int newLimit) 设置limit的值,并返回一个新的limit缓冲区对象
Buffer mark() 设置Buffer的标记(mark),只能在0与position之间做标记
int position() 获取Buffer中position的值
Buffer position(int newPosition) 设置Buffer的position,并返回位置被修改之后的Buffer对象
int remaining() 获取当前位置和界限之间的元素个数
Buffer reset() 将此缓冲区的位置重置为先前标记的位置
Buffer rewind() 倒带缓冲区,将position设置为0,并取消设置的标记

除上表中的方法外,Buffer的所有子类中都额外提供了put()和get()方法用于向Buffer中放入数据和取出数据。在使用put()和get()方法放入和取出数据时,Buffer既支持单个数据的访问,也支持批量数据的访问。

对Buffer类有了一定的了解后,下面通过一个具体的案例来演示Buffer的使用,如文件1所示。

文件1 Example18.java

 1    import java.nio.CharBuffer;
 2    public class Example18 {
 3        public static void main(String[] args){
 4             // 创建CharBuffer对象,并指定缓冲区容量大小为6
 5            CharBuffer charBuffer = CharBuffer.allocate(6);
 6            System.out.println("容量:" + charBuffer.capacity());
 7            System.out.println("界限值:" + charBuffer.limit());
 8            System.out.println("初始位置:" + charBuffer.position());
 9            // 向CharBuffer对象中放入3个元素
 10            charBuffer.put('x');
 11            charBuffer.put('y');
 12            charBuffer.put('z');
 13             System.out.println("加入元素后的界限值:" + charBuffer.limit());
 14            System.out.println("加入元素后的位置:" + charBuffer.position());
 15            // 执行flip()方法
 16            charBuffer.flip();
 17            System.out.println("执行flip()后的界限值:" + charBuffer.limit());
 18            System.out.println("执行flip()后的位置:" + charBuffer.position());
 19            // 取出第1个元素
 20            System.out.println("取出的第1个元素为:" + charBuffer.get());
 21            System.out.println("取出后的界限值:" + charBuffer.limit());
 22            System.out.println("取出后的位置:" + charBuffer.position());
 23            // 执行clear()方法
 24            charBuffer.clear();
 25            System.out.println("执行clear()后的界限值:" + charBuffer.limit());
 26            System.out.println("执行clear()后的位置:" + charBuffer.position());
 27            // 取出第1个元素
 28            System.out.println("取出的第1个元素为:" + charBuffer.get(0));
 29            System.out.println("取出后的界限值:" + charBuffer.limit());
 30            System.out.println("取出后的位置:" + charBuffer.position());    
 31        }
 32    }

运行结果如图2所示。

图2 运行结果

文件1中,首先创建了一个容量为6的CharBuffer对象,并输出了该对象的容量、界限以及初识位置值;然后向CharBuffer对象中放入了3个字符元素,并输出了加入元素后的位置,从输出结果可以看出,元素位置已经发生了变化。接下来执行了flip()方法并再次输出界限值和位置,此时界限值已由原来的6变为3,位置由3变为了0,这是因为调用了flip()方法之后,limit会移动到到原来的position的位置,而position会被设置为0。接着通过get()方法取出了对象中的第1个元素,并输出此时的界限值和位置,从输出结果可以看出,界限值没有变,而位置变为1,这是因为取出一个元素后,position会向后移动一位。程序继续向下执行完clear()方法后,limit会被设置为与容量相等,而position会被设置为0。最后通过索引的方式取出第1个元素的值,并输出界限值和位置。从运行结果可以看出,执行完clear()方法之后,Buffer对象中的数据依然存在,并且通过索引取出元素值后,position的值并没有受到影响。

点击此处
隐藏目录