ByteBuffer 是一个字节缓冲区,在java.nio 包,原生NIO 的参数都已经使用ByteBuffer对象,是对byte 数组的封装,通过ByteBuffer API简化对于缓存区字节的操作。
ByteBuffer 可以通过 allacation 方法分配字节内容的空间,或是通过 wrap 方法,将一个字节数组包装成一个ByteBuffer。
类型
ByteBuffer 有两种类型:直接内存、非直接内存类型。
直接内存:DirectByteBuffer, 底层数据是维护在操作系统内存中,不在jvm,只维护引用地址指向数据。通常从外部设备读取时,jvm从这个外部设备的数据读取到一个内存块,再从这个内存块读取。但是使用DirectByteBuffer 不需要从外部设备读取到内存,可以直接读取。
非直接内存:HeapByteBuffer,在jvm堆上维护的一个buffer,底层是一个数组。
数据结构
- capacity 缓存区的容量. 该值不允许负值,也不允许修改
- opsition下一个可读或可写的位置
- limit 缓存区里第一个不能读或不能写的位置,该值不会是负值,同时也不会大于capacity
- mark 标志位
几个字段的关系 mark <=position <=limit <=capacity
举例(结合后面的图进行观察变化)
public static void main(String[] args) {
//1. 分配容量为10 ,默认是 HeapByteBuffer
ByteBuffer buffer = ByteBuffer.allocate(10);
//ByteBuffer buffer = ByteBuffer.allocateDirect(10);// 创建直接内存缓存
//2. 写入4个字节
buffer.put(new byte[]{10, 2, 3, 4});
System.out.println(String.format("写模式下:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
System.out.println("切换为读模式");
//3. 切换为读模式
buffer.flip();
System.out.println(String.format("读模式下:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
System.out.println("读取数据");
//4. 读取数据
while (buffer.hasRemaining()) {
System.out.println(buffer.get());
}
System.out.println(String.format("读取数据后:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
System.out.println("设置pos=1");
//5. 重新设置pos=1
buffer.position(1);
//6. 调用compact 进行数据压缩
buffer.compact();
System.out.println(String.format("compact后:pos=%d, limit=%d, capacity=%d", buffer.position(), buffer.limit(), buffer.capacity()));
while (buffer.hasRemaining()) {
System.out.println(buffer.get());
}
buffer.flip();
//7. 测试mark & reset
System.out.println("测试mark&rest 读取一个数据");
System.out.println(buffer.get());
System.out.println("mark的pos=" + buffer.position());
buffer.mark();
// 读完剩下的内容
while (buffer.hasRemaining()) {
System.out.println(buffer.get());
}
System.out.println("reset前的pos=" + buffer.position());
// 重置标识
buffer.reset();
System.out.println("reset后的pos=" + buffer.position());
}
- 初始容量
- 写入4字节
- 切换为读模式(flip)
- 读取全部数据
- 设置pos =1,数据进行压缩(compact),会切换成写模式
- mark & reset
mark 会记录下当下的pos,后面调用reset 可以重置这个pos为mark的值
- rewind & clear
rewind 会重置 pos = 0,mark =-1,limit不变
clear 会重置pos = 0,limit = capacity, mark = -1,但底层的数组不变,重新写入会覆盖内部数组的数据。