NIO三大组件之Buffer
什么是Buffer
Buffer(这里并不是特指Buffer类)是一个存储数据的容器,与数组类似(其实底层依旧是用数组的结构来存储数据),但不同的是,Buffer对象提供了一组更有效的方法去进行写入和读取的交替访问
Buffer类的特性
线程安全性
Buffer是线程不安全的,所以如果有多于一个线程去访问,那么需要手动加上同步操作
关键属性
capacity
是Buffer对象的能容纳的最大的元素个数(类似于数组的长度,但不一定是字节数组),不能为负,不能改变
limit
是第一个不能够被读或者被写的元素的位置(即能够被读和写的最大元素个数),要小于等于capacity
例如,在默认情况下limit=capacity,当capacity=10时,limit=10说明有索引0-9是可以访问的,也可以把limit理解为可以访问的元素的个数
position
是当前可以读取或者写入的元素的位置,要小于等于limit
在写入模式时,position初始为0,每有一个数据写入,则后移一位,最大值为limit-1
比如limit限制为10,则可以访问的索引为0-9共十个数,那么当position=9时是可写的,但当position=10时,就不可写了;
在读入模式时,position也是默认从零开始,但是由于调用flip()时会把position赋值给limit,所以position<=limit
例如当写入模式已经写入了index为9的元素,position此时为10,读状态时limit也为10
mark
可以暂时存储所需要的position的值,方便以后回到此位置,与其名字一样,起到标记的作用
0 <= mark <= position <= limit <= capacity
关键方法
flip
用于将写模式转换为读模式
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
clean
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
可以看出来,虽然名字叫做clean,但却没有真的去清除数据,只是改变了position和limit而已,却在事实上与清除数据有同样的效果,同时将读模式转换为写模式
compact
这个方法也可以把读模式变成写模式
reset
此方法把position恢复到mark的位置上
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
rewind
表示将之前的数据再读一次
其实这几个方法主要都是limit,position与mark这三个变量的值的转换
分类
所有的xxxBuffer类都继承了Buffer类,有各种原生类的buffer,其中byte类型的buffer又根据字符编码分为多种,但所有这些类都是抽象类或者不能直接从外部访问的类
而我们所使用的类一般都是以direct或者heap开头的实现类.这也是allocate()方法的返回值
这里以ByteBuffer源码为例
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
问题
Java NIO中是怎么判断一个buffer是读模式还是写模式的呢?