什么是Buffer?
Buffer即缓冲区的意思,缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象,该对象提供了一组方法,可以轻松的使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况;
Buffer类及子类
Buffer为缓冲区的父类,以下是常用子类:
类名 | 描述 |
---|---|
ByteBuffer | 存储字节数据 |
CharBuffer | 存储字符数据 |
ShortBuffer | 存储短整形数据 |
IntBuffer | 存储短整型数据 |
LongBuffer | 存储长整型数据 |
DoubleBuffer | 存储双精度浮点数据 |
FloatBuffer | 存储单精度浮点数据 |
Buffer类定义的所有的缓冲区都具有四个属性来提供其存储的元素信息:
属性名 | 描述 |
---|---|
mark | 标记 |
position | 操作缓冲区的位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变此值,为下次读写做准备 |
limit | 表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作,但极限是可以修改的 |
capacity | 容量,即可以容纳的最大数据量,在缓冲区创建时被设定并且不能改变 |
Buffer类常用方法列表:
方法名 | 描述 | jdk版本 |
---|---|---|
public final int capacity() | 返回此缓冲区的容量 | 1.4 |
public final int position() | 返回此缓冲区的位置 | 1.4 |
public final Buffer position (int newPositio) | 设置此缓冲区的位置 | 1.4 |
public final int limit() | 返回此缓冲区的限制 | 1.4 |
public final Buffer limit (int newLimit) | 设置此缓冲区的限制 | 1.4 |
public final Buffer mark() | 在此缓冲区的位置设置标记 | 1.4 |
public final Buffer reset() | 将此缓冲区的位置重置为以前标记的位置 | 1.4 |
public final Buffer clear() | 清除此缓冲区, 即将各个标记恢复到初始状态,但是数据并没有真正擦除, 后面操作会覆盖 | 1.4 |
public final Buffer flip() | 反转此缓冲区 | 1.4 |
public final Buffer rewind() | 重绕此缓冲区 | 1.4 |
public final int remaining() | 返回当前位置与限制之间的元素数 | 1.4 |
public final boolean hasRemaining() | 告知在当前位置和限制之间是否有元素 | 1.4 |
public abstract boolean isReadOnly() | 告知此缓冲区是否为只读缓冲区 | 1.4 |
public abstract boolean hasArray() | 告知此缓冲区是否具有可访问的底层实现数组 | 1.6 |
public abstract Object array() | 返回此缓冲区的底层实现数组 | 1.6 |
public abstract int arrayOffset() | 返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量 | 1.6 |
public abstract boolean isDirect() | 告知此缓冲区是否为直接缓冲区 | 1.6 |
从前面可以看出对于 Java 中的基本数据类型(boolean除外),都有一个Buffer类型与之相对应,最常用的自然是ByteBuffer类(二进制数据),该类的主要方法如下:
方法名 | 描述 |
---|---|
public static ByteBuffer allocateDirect(int capacity) | 创建直接缓冲区 |
public static ByteBuffer allocate(int capacity) | 设置缓冲区的初始容量 |
public static ByteBuffer wrap(byte[] array) | 把一个数组放到缓冲区中使用 |
public static ByteBuffer wrap(byte[] array,int offset, int length) | 构造初始化位置offset和上界length的缓冲区 |
public abstract byte get() | 从当前位置position上get,get之后,position会自动+1 |
public abstract byte get (int index) | 从绝对位置get |
public abstract ByteBuffer put (byte b) | 从当前位置上添加,put之后,position会自动+1 |
public abstract ByteBuffer put (int index, byte b) | 从绝对位置上put |
Buffer使用示例
public class BasicBuffer {
public static void main(String[] args) {
// 创建一个大小为10的int类型的buffer
IntBuffer intBuffer = IntBuffer.allocate(10);
// 向buffer中存放数据
for (int i = 0; i < 10; i++) {
intBuffer.put(i);
}
// 读取buffer之前需要进行反转
intBuffer.flip();
// 遍历buffer,读取buffer数据
while (intBuffer.hasRemaining()) {
System.out.println(intBuffer.get());
}
}
}
Buffer使用注意事项
- ByteBuffer支持类型化的put和get,put放入的是什么类型,get就应该使用相应的数据类型来取出,否则可能出现BufferUnderflowException异常,如下代码所示:
public class ByteBufferPutGet {
public static void main(String[] args) {
// 创建一个buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(8);
byteBuffer.putChar('陈');
byteBuffer.putInt(1);
byteBuffer.putShort((short) 9);
// 反转
byteBuffer.flip();
// System.out.println(byteBuffer.getLong());
System.out.println(byteBuffer.getChar());
System.out.println(byteBuffer.getInt());
System.out.println(byteBuffer.getShort());
}
}
- 普通buffer设置为只读buffer,如果往只读buffer里面添加数据则会抛出ReadOnlyBufferException,如下代码所示:
public class ReadOnlyBuffer {
public static void main(String[] args) {
IntBuffer intBuffer = IntBuffer.allocate(8);
for (int i = 0; i < 8; i++) {
intBuffer.put(i);
}
// 反转
intBuffer.flip();
// 得到一个只读的buffer
IntBuffer readOnlyBuffer = intBuffer.asReadOnlyBuffer();
System.out.println("readOnlyBuffferClass:"+readOnlyBuffer.getClass());
while (readOnlyBuffer.hasRemaining()) {
System.out.println(readOnlyBuffer.get());
}
readOnlyBuffer.put(99); // 此处会抛出ReadOnlyBufferException
}
}