Java NIO 三大组件之 Buffer

2019-12-03 来源: ilmostro 发布在  https://www.cnblogs.com/mostro/p/11977276.html

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申请内存空间。(实质是堆)
两种方式的优缺点
  1. 非直接缓冲区有JVM到OS这段中间开销,使得访问性能下降。但是由于缓存在JVM堆中,数据受程序控制。
  2. 直接缓冲区没有中间开销,但由于内存是向OS申请,缓冲区的数据存储不受程序的控制。

相关文章