1. 程式人生 > >Java NIO 三大元件之 Buffer

Java NIO 三大元件之 Buffer

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申請,緩衝區的資料儲存不受程式的控制。