NIO从整体上分类来看可以看做由这几个部分组成:Buffer,Channel,Selector组成。本篇文章从浅谈一下Buffer。
1:Buffer的类型。可以这么来说,不同的数据类型有不同的buffer,例如ByteBuffer,IntBuffer,LongBuffer,ShortBuffer。。分别对应的数据类型为byte,int,long,short。
2:想获取一个Buffer对象的话首先要进行buffer对象的分配,每一个Buffer类都有一个allocate的方法。具体用法:
ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
观察如上的代码,创建一个具体的Buffer对象都要使用相关的Buffer类的allocate方法。到这里,可能就会有同学有疑问了,为什么不能直接new出来。下面,进入ByteBuffer源码里看一眼。
public abstract class ByteBuffer
extends Buffer
implements Comparable
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
估计可以看出一些门道来了,ByteBuffer是一个抽象类,allocate是抽象类中的静态方法,通过allocate方法构造的是HeapByteBuffer对象。
由此,推断出其他数据类型的Buffer也是一个抽象对象,通过allocate方法构造出具体的对象来。因此,又去IntBuffer源码中看了一眼,果不其然,如下图:
public abstract class IntBuffer
extends Buffer
implements Comparable
public static IntBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapIntBuffer(capacity, capacity);
}
接下来,为了理解buffer的工作原理,看下buffer的三个属性
capacity【容量】
position【位置】
limit【界限】
关于这三个属性之间的关系,找了一个比较易懂的图片来解释下
左边的代表写入的时候,右边的代表读取的时候
当写入的时候,capacity的大小代表利用allocate初始化时候的大小,代表这个缓存块的容量,最多只能向这个缓存块中放入capacity个char,long,int,byte等等。当缓存块满了的时候需要将其清空,才能继续往里面写数据
position:代笔当前位置,初始化值为0,当一个数据写入buffer中的时候,position会移动到下一个可插入的buffer单元,因此,position的最大值为position-1,
limit:在写的模式下面,limit表示你最多可以向buffer里面写入多少个buffer数据,在写模式下面,limit=capacity。
当切换到读模式下面,代表最多能读取到多少数据。因此当切花到读模式下面,limit会被置为写模式下面的position值。因此,你能读取到在写模式下面写入的所有值。
以上的话,就是这三个属性的具体介绍。
理解了这三个属性之后,对于理解buffer的一些方法有很大的用处。
1:rewind方法:主要是讲position置为0,因此,我们可以从头开始重新读取一遍数据,limit保持不变。
2:clear与compact方法。当读取完数据之后可以通过这两个方法来继续让buffer准备好继续写入
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
因此,通过clear的方法之后,会将position置为0,limit置为容器大小,相当远将容器清空,所以这时候即使有未处理的数据也不会再被读取出来。
但是compact方法,会将position置为 limit-position,意味着什么,假设limit=10,position=3,意味着这个缓存块我们已经读到第三个,还剩下7个没有读,最新的position=7,也就是最新一次存数据会从第7个开始写,并且会将原来未读取的数据copy一份放在前7个块中。
public ByteBuffer compact() {
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
position(remaining());
limit(capacity());
discardMark();
return this;
}
flip 当我们从写模式切换到读模式的时候使用。
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
理解了这三个属性的意思之后,看下代码直接明白什么意思了,将limit=position。意思为在读模式下可以读取最多的数据是多少,position=0说明读取开始的位置。