簡單認識java中的bytebuffer和netty中的bytebuf

一 nio中的bytebuffer的認識

1.bytebuffer的數據結構

對於ByteBuffer,其主要有五個屬性:mark,position,limit,capacity和array。這五個屬性的作用如下:
mark:記錄了當前所標記的索引下標;
position:對於寫入模式,表示當前可寫入數據的下標,對於讀取模式,表示接下來可以讀取的數據的下標;
limit:對於寫入模式,表示當前可以寫入的數組大小,默認爲數組的最大長度,對於讀取模式,表示當前最多可以讀取的數據 的位置下標;
capacity:表示當前數組的容量大小;
array:保存了當前寫入的數據。
這幾個數據中,除了array是用於保存數據的以外,這裏最終的主要是position,limit和capacity三個屬性,因爲對於寫入和讀取模式,這三個屬性的表示的含義大不一樣。

1.1寫入模式:

如下圖所示爲初始狀態和寫入3個字節之後position,limit和capacity三個屬性的狀態:

從圖中可以看出,在寫入模式下,limit指向的始終是當前可最多寫入的數組索引下標,position指向的則是下一個可以寫入的數據的索引位置,而capacity則始終不會變化,即爲數組大小。

注意:圖片來源知乎,如果侵權,聯繫我刪除

1.2讀取模式
假設我們按照上述方式在初始長度爲6的ByteBuffer中寫入了三個字節的數據,此時我們將模式切換爲讀取模式,那麼這裏的position,limit和capacity則變爲如下形式:

在這裏插入圖片描述
可以看到,當切換爲讀取模式之後,limit則指向了最後一個可讀取數據的下一個位置,表示最多可讀取的數據;position則指向了數組的初始位置,表示下一個可讀取的數據的位置;capacity還是表示數組的最大容量。這裏當我們一個一個讀取數據的時候,position就會依次往下切換,當期與limit重合時,就表示當前ByteBuffer中已沒有可讀取的數據了。

注意:圖片來源知乎,如果侵權,聯繫我刪除

1.3下面用代碼來說明相關api

flip:切換爲讀取模式
mark:這個屬性是一個標識的作用,即記錄當前position的位置,
在後續如果調用reset()或者flip()方法時,ByteBuffer的position就會被重置到mark所記錄的位置。
因而對於寫入模式,在mark()並reset()後,將會回到mark記錄的可以寫入數據的位置;
對於讀取模式,在mark()並reset()後,將會回到mark記錄的可以讀取的數據的位置
代碼打印運行結果:

         ByteBuffer buffer = ByteBuffer.allocate(6);
        System.out.println(buffer);
        
        buffer.put((byte) 1);
        buffer.put((byte) 2);
        buffer.put((byte) 3);

        buffer.mark();
        buffer.put((byte) 4);

        System.out.println("put後=======>" + buffer);

        buffer.reset();
        System.out.println("reset後=======>" + buffer);


        buffer.flip();
        System.out.println("flip後===>" + buffer);
        
        buffer.get();
        System.out.println("get後===>" + buffer);

        buffer.mark();
        System.out.println("再次mark後===>" + buffer);


        buffer.reset();
        System.out.println("再次reset後===>" + buffer);

運行結果如下:
java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]
put後=======>java.nio.HeapByteBuffer[pos=4 lim=6 cap=6]
reset後=======>java.nio.HeapByteBuffer[pos=3 lim=6 cap=6]
flip後===>java.nio.HeapByteBuffer[pos=0 lim=3 cap=6]
get後===>java.nio.HeapByteBuffer[pos=1 lim=3 cap=6]
再次mark後===>java.nio.HeapByteBuffer[pos=1 lim=3 cap=6]
再次reset後===>java.nio.HeapByteBuffer[pos=1 lim=3 cap=6]

二:netty中的bytebuf
1.數據結構
在這裏插入圖片描述
可以看出提供了兩個pointer來操作buf。
2.相關api
因api太多,我只是用demo測試一下,常用的api。如果想看更詳細的請移步官網https://netty.io/3.10/api/index.html

        ByteBuf buf = Unpooled.buffer();
        byte[] bytes = "zpf wants to be a good coder".getBytes();
        buf.writeBytes(bytes);
        System.out.println("寫入byte數組後的buf==>"+buf);

        int readCount = buf.readableBytes();
        System.out.println("可讀的長度爲==>"+readCount);


        byte[] readableBytes = new byte[readCount];

        buf.readBytes(readableBytes);
        System.out.println("調用buf.read之後的byteBuf==>"+buf);


        ByteBuf clear = buf.clear();
        System.out.println("clear後==>"+buf);
        System.out.println("clear後的clear==>"+clear);


        ByteBuf discardReadBytes = buf.discardReadBytes();


        System.out.println("調用discardReadBytes後的buf==>"+buf);
        System.out.println("discardReadBytes的值==>"+discardReadBytes);



        String s = new String(readableBytes,"UTF-8");
        System.out.println("再轉回來String==>"+s);

運行結果如下:
寫入byte數組後的buf==>UnpooledHeapByteBuf(ridx: 0, widx: 28, cap: 256)
可讀的長度爲==>28
調用buf.read之後的byteBuf==>UnpooledHeapByteBuf(ridx: 28, widx: 28, cap: 256)
clear後==>UnpooledHeapByteBuf(ridx: 0, widx: 0, cap: 256)
clear後的clear==>UnpooledHeapByteBuf(ridx: 0, widx: 0, cap: 256)
調用discardReadBytes後的buf==>UnpooledHeapByteBuf(ridx: 0, widx: 0, cap: 256)
discardReadBytes的值==>UnpooledHeapByteBuf(ridx: 0, widx: 0, cap: 256)
再轉回來String==>zpf wants to be a good coder

三:nio中的byteBuffer和netty中的bytebuf的區別

1.ByteBuffer必須自己長度固定,一旦分配完成,它的容量不能動態擴展;ByteBuf默認容器大小爲256,支持動態擴容,在允許的最大擴容範圍內(Integer.MAX_VALUE)。

2.ByteBuffer只有一個position標識位置的指針,讀的時候需要手動的調用flip()和rewind()等,否則很容易導致程序處理失敗。而ByteBuf有兩個標識位置的指針,一個寫writerIndex,一個讀readerIndex,讀寫的時候不需要調用額外的方法。

3.NIO的SocketChannel進行網絡讀寫時,操作的對象是JDK標準的java.nio.byteBuffer。由於Netty使用統一的ByteBuf替代JDK原生的java.nio.ByteBuffer,所以ByteBuf中定義了ByteBuffer nioBuffer()方法將ByteBuf轉換成ByteBuffer。

嗯,應該還有差異,以上是我目前的瞭解,最近在看netty權威指南,如果有新的理解,會在及時記錄一下。

部分內容參考知乎:https://zhuanlan.zhihu.com/p/56876443

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章