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 申请, 缓冲区的数据存储不受程序的控制.
来源: https://www.cnblogs.com/mostro/p/11977276.html