NIO大三组件 之Buffer
一、什么是Buffer
Buffer是用于特定原始类型的数据的容器。 它的实质就是一组数组,用于存储不同类型的数据。
二、缓冲区的类型
缓冲区类型除了Boolean值类型外,其余基本类型都含有。
NIO中定义的抽象缓冲区对象如下(均继承至Buffer抽象类):
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
上述类均为抽象类,它们的实现还分有直接缓冲区和非直接缓冲区。
三、缓冲区中的四个核心属性
- category: 容量,表示缓冲区的大小,一旦声明就不可改变。
- limit: 界限,表示缓冲区中可以操作数据的大小。(llimit后面的数据不可读写)
- position: 位置,表示缓冲区中正在操作数据的位置。
- mark: 标记,可以标记当前position的位置。
写操作
进行写操作时,limit=category,limit
表示的是可以写的地址范围。
而position
则表示当前写的索引,每写一个字节position则+1。
读操作
进行读操作时,limit=position,limit
此时则表示可读取的范围,此时范围则会被赋值为写的position
。
而当position
赋值完给limit
后,position
则置零。在读操作中position
则表示读的索引。
它们之间的关系
mark <= position <= limit <= capacity
@Test
public void markTest(){
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocate(1024);
byte[] bytes = new byte[10];
buf.put(str.getBytes());
//切换到读模式
buf.flip();
//获取buf的两个字节
buf.get(bytes, 0, 2);
System.out.println(new String(bytes));
//标记position的位置
buf.mark();
//获取buf的两个字节
buf.get(bytes, 2, 2);
System.out.println(new String(bytes));
System.out.println(buf.position());
//回到position=2的位置
buf.reset();
System.out.println(buf.position());
}
四、存取缓冲区数据的核心方法
- put():存入数据到缓冲区中
- get(): 获取缓冲区中的数据
- flip(): 读写切换
- clear():清空写缓存,,只是把position和limit重置为最初状态,但是缓存区的内容并没有删除
- mark(): 保存当前position的位置
- reset(): 把当前的position重置为mark的值
- rewind(): 重读操作,position置0
@Test
public void bufferMethodTest(){
String str = "abcde";
//声明一个Byte缓冲区(非直接缓冲区),并设置缓冲区大小为1024
ByteBuffer buf = ByteBuffer.allocate(1024);
//直接缓冲区申请方式
//ByteBuffer.allocateDirect(1024);
System.out.println("-------------------------allocate------------------------");
//0
System.out.println(buf.position());
//1024
System.out.println(buf.limit());
//1024
System.out.println(buf.capacity());
System.out.println("-------------------------put------------------------");
//把str的数据放入缓冲区
buf.put(str.getBytes());
//5
System.out.println(buf.position());
//1024
System.out.println(buf.limit());
//1024
System.out.println(buf.capacity());
//3.切换读取数据模式
buf.flip();
System.out.println("-------------------------get------------------------");
byte[] bytes = new byte[20];
//读取缓冲区理的5个字节
buf.get(bytes,0, buf.limit());
//5,表示数据读到的位置
System.out.println(buf.position());
//5.表示可以读的位置
System.out.println(buf.limit());
System.out.println(buf.capacity());
//5. rewind: 可重读
buf.rewind();
System.out.println("-------------------------rewind------------------------");
//position回到0
System.out.println(buf.position());
//5.表示可以读的位置,5
System.out.println(buf.limit());
System.out.println(buf.capacity());
//clear(): 清空缓存区,但数据任然存在,只是把position和limit重置为最初状态。
buf.clear();
System.out.println("-------------------------clear------------------------");
//postion变为0
System.out.println(buf.position());
//1024
System.out.println(buf.limit());
System.out.println(buf.capacity());
}
五、补充
关于直接缓冲区与非直接缓冲区
- 直接缓冲区: 缓冲区地址直接映射到磁盘地址。
- 非直接缓冲区: 缓冲区地址先通过JVM缓存,然后再由JVM向OS申请内存空间。(实质是堆)
两种方式的优缺点
- 非直接缓冲区有JVM到OS这段中间开销,使得访问性能下降。但是由于缓存在JVM堆中,数据受程序控制。
- 直接缓冲区没有中间开销,但由于内存是向OS申请,缓冲区的数据存储不受程序的控制。