关键词:ByteBuffer NIO
ByteBuffer是java.nio包下的类,看见nio就会想到,它与非阻塞IO是有关系的。ByteBuffer有很多兄弟姐妹,比如:CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer等。这些类都有共同的父类Buffer。见名思意,ByteBuffer是操作字节数据的,IntBuffer是操作整形数据的。在ByteBuffer维护了一个byte[] hb数组,在IntBuffer里维护了一个int[] hb数组。
█ 总体认识
类图:
相关概念:
ByteBuffer分两种,Direct和non-direct buffers。Direct buffer有MappedByteBuffer、DirectByteBuffer、DirectByteBufferR。non-direct buffer有HeapByteBuffer和HeapByteBufferR。Direct buffer即操作直接内存,直接内存指内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)。通过调用方法allocateDirect(int)来获取直接内存buffer。non-direct buffer即操作堆内存。通过方法allocate(int)获取。(点击查看直接内存的解释)。HeapByteBufferR和DirectByteBufferR,在拼写上多了个R,这个R是read-only(只读)的意思。
ByteBuffer继承自Buffer,在Buffer中定义了下面四个int类型的属性:
capacity:一个buffer的capacity是指它所包含的元素数量。该值永远不会为负数,也永远不会改变。(给定了初始值之后就不会改变了)。对于non-direct buffers,在内部维护一个字节数组用于存放元素,这里的capacity大小也就是指定了这个数组的大小。
limit:是buffer中第一个不能够被读取或写入的元素的索引值(元素是存放在数组中的,元素的索引值即数组的下标),该值永远不会为负数,并且不能比capacity值大。
position:和limit相对,是buffer中第一个能够被读取或写入的元素的索引值。该值永远不会为负数,并且不能比limit值大。初始化的时候为0,每往buffer存放数据,position的值都会加1。
mark:定义了这样的一个元素索引值,当调用reset方法时,position的值就等于mark值。若没有定义,调用reset方法会报InvalidMarkException。这个值从来不会被定义,但是一旦被定义,该值永远不会为负数,并且不能比position的值大。当定义了mark,如果调整之后的position或limit的值小于了mark值,则mark值会失效(值为-1)。mark未被定义时的值是-1,一旦被定义,值就不能是负数了。
由此可见,上面四个属性的大小关系是:0<=mark<=position<=limit<=capacity。一个新创建的buffer,position初始化为0,mark不会被定义,即值为-1。从limit、position的定义可以看出,最大的数据读取或写入长度是limit减去position。若position=0,limit=5,则此时最大的读取存放数据的长度就是5。数组的下标范围其实是从0到4。可以理解成是一种左闭右开的关系,即包括position的位置,不包括limit的位置。也可以说是读取存放数据的数组下标是从position开始到limit-1的下标位置。记住position和limit的意义和关系,就方便理解ByteBuffer了。
还有一个属性:offset。当前与position与下一次position(position+1)的偏移量。是在position加1之后再进行相加的值,来确定元素的起始位置。默认值为0。可以认为是通过position和offset来确定元素的数组下标的。
若offect=0,添加元素时的情况是这样的:
若offect=2,添加元素时的情况是这样:
█ non-direct buffers
①创建初始化
// 通过方法创建堆内buffer,这里是创建一个capacity为10的buffer。
// buffer在内部维护了一个字节数组final byte[] hb,这里的10也就是初始化了数组的长度。
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
// 创建的是HeapByteBuffer对象,第一个参数是指定capacity的值,第二个参数是指定limit的值。
return new HeapByteBuffer(capacity, capacity);
}
HeapByteBuffer(int cap, int lim) {
// 注意这里的new byte[cap]
// supper调用了ByteBuffer的构造函数
super(-1, 0, lim, cap, new byte[cap], 0);
}
ByteBuffer(int mark, int pos, int lim, int cap,
byte[] hb, int offset)
{
super(mark, pos, lim, cap);
// 初始化了一个大小为capacity的字节数组,并赋给