Buffer介绍
Buffer是一个包含了固定大小的特定原生类型数据的容器。定义了标示可读和可写范围的指示器,以及,clearing/flipping/rewinding等方法来标记当前操作位置、重置位置到之前标记的位置。
Buffer抽象类源码
public abstract class Buffer {
// 0 <= mark <= position <= limit <= capacity
private int mark = -1;//标记的位置
private int position = 0;//下一个读取或者写入的元素的位置
private int limit;//可以读取或者写入的最大值+1(第一个不允许读或者写)
private int capacity;//buffer的大小,值固定。
// Used only by direct buffers
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
//构造方法
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException();
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException();
this.mark = mark;
}
}
//相当于get方法
public final int capacity() {
return capacity;
}
public final int position() {
return position;
}
public final int limit() {
return limit;
}
//相当于set方法
public final Buffer position(int newPosition) {
//newPosition不能大于当前的limit
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
//如果新位置小于mark,mark=-1
if (mark > position)
mark = -1;
return this;
}
public final Buffer limit(int newLimit) {
//newLimit必须<=capacity
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
//如果limit减小了小于了position
if (position > limit)
position = limit;
if (mark > limit)
mark = -1;
return this;
}
//标记当前位置
public final Buffer mark() {
mark = position;
return this;
}
//重置,position变为之前mark()操作设置的mark
public final Buffer reset() {
int m = mark;
//没有调用过mark()方法
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
//清空buffer,所有数据不能再读了,可以写入。
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
//翻转buffer,写入完成,可以读取。
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
//写入完成,可以读取,limit需要保证已经提前设置
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
//剩余可读取或者可写入的数量
public final int remaining() {
return limit - position;
}
//是否可写入或者可读
public final boolean hasRemaining() {
return position < limit;
}
//是否只读
public abstract boolean isReadOnly();
//是否是由数组实现
public abstract boolean hasArray();
//如果是有数组实现且buffer不是只读buffer返回数组。
public abstract Object array();
//buffer的第一个元素在array中的位置??
public abstract int arrayOffset();
//是否是direct buffer
public abstract boolean isDirect();
// -- Package-private methods for bounds checking, etc. --
//获得下一个读取的位置,且位置+1
final int nextGetIndex() {
if (position >= limit)
throw new BufferUnderflowException();
return position++;
}
//获得下一个读取的位置,且位置+nb
final int nextGetIndex(int nb) {
if (limit - position < nb)
throw new BufferUnderflowException();
int p = position;
position += nb;
return p;
}
//获取下一个插入位置,且位置+1
final int nextPutIndex() {
if (position >= limit)
throw new BufferOverflowException();
return position++;
}
//获取下一个插入位置,且位置+nb
final int nextPutIndex(int nb) {
if (limit - position < nb)
throw new BufferOverflowException();
int p = position;
position += nb;
return p;
}
//检查位置是否合法
final int checkIndex(int i) {
if ((i < 0) || (i >= limit))
throw new IndexOutOfBoundsException();
return i;
}
final int checkIndex(int i, int nb) {
if ((i < 0) || (nb > limit - i))
throw new IndexOutOfBoundsException();
return i;
}
final int markValue() {
return mark;
}
final void truncate() {
mark = -1;
position = 0;
limit = 0;
capacity = 0;
}
//检查范围,从off开始读取len的数据,是否超出了size
static void checkBounds(int off, int len, int size) {
if ((off | len | (off + len) | (size - (off + len))) < 0)
throw new IndexOutOfBoundsException();
}
}
Buffer以及各子类
1:ByteBuffer
是个抽象类
http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html
提供的操作:
1:绝对和相对位置的单个字节的get/put方法
2:相对位置的批量字节的get
3:相对位置的批量字节的put
4:绝对和相对位置的其他原生类型的get/put方法【涉及byte order】
5:获取其他原生类型的视图buffer
6:压缩、复制、切片buffer
ByteBuffer可以通过静态方法allocation方法创建一定capacity的buffer,或者包装现有的byte array
ByteBuffer有两类:direct/non-direct。direct buffer直接在操作系统内存分配,non-direct buffer在jvm 堆中分配。direct buffer的IO直接在操作系统内存操作,避免了操作系统内容和堆内存的复制开销,效率高。但是创建和销毁代价比较高;
direct buffer可以通过allocateDirect静态方法创建;也可以通过file的mapping方法创建;
除了boolean其他的原生类型,都可以直接读写buffer,数据类都占用多个字节,要注意直接的顺序(ByteOrder定义,BIG_ENDIAN).
绝对位置的读写: float getFloat() void putFloat(float f)对buffer的当前position操作;
相对位置的读写:float getFloat(int index)void putFloat(int index, float f) 从第index个字节开始读写。
视图buffer:
可以通过asFloatBuffer类似的方法创建FloateBuffer等视图buffer,内部仍然是以byte buffer实现。
视图Buffer的index不是指字节而是原生数据
1.1 MappedByteBuffer
通过FileChannel.map方法创建。
A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.【?direct buffer也受到GC的控制吗】
MappedByteBuffer的内容会动态发生变化,如果映射文件的内容发生变化。何事发生变化、是否发生变化是于操作系统相关的。
MappedByteBuffer的内容可能会不可操作。