Netty剖析之NIO-Buffer

什麼是Buffer?

Buffer即緩衝區的意思,緩衝區本質上是一個可以讀寫數據的內存塊,可以理解成是一個容器對象,該對象提供了一組方法,可以輕鬆的使用內存塊,緩衝區對象內置了一些機制,能夠跟蹤和記錄緩衝區的狀態變化情況;

Buffer類及子類

Buffer爲緩衝區的父類,以下是常用子類:

類名 描述
ByteBuffer 存儲字節數據
CharBuffer 存儲字符數據
ShortBuffer 存儲短整形數據
IntBuffer 存儲短整型數據
LongBuffer 存儲長整型數據
DoubleBuffer 存儲雙精度浮點數據
FloatBuffer 存儲單精度浮點數據

Buffer類定義的所有的緩衝區都具有四個屬性來提供其存儲的元素信息:

屬性名 描述
mark 標記
position 操作緩衝區的位置,下一個要被讀或寫的元素的索引,每次讀寫緩衝區數據時都會改變此值,爲下次讀寫做準備
limit 表示緩衝區的當前終點,不能對緩衝區超過極限的位置進行讀寫操作,但極限是可以修改的
capacity 容量,即可以容納的最大數據量,在緩衝區創建時被設定並且不能改變

Buffer類常用方法列表:

方法名 描述 jdk版本
public final int capacity() 返回此緩衝區的容量 1.4
public final int position() 返回此緩衝區的位置 1.4
public final Buffer position (int newPositio) 設置此緩衝區的位置 1.4
public final int limit() 返回此緩衝區的限制 1.4
public final Buffer limit (int newLimit) 設置此緩衝區的限制 1.4
public final Buffer mark() 在此緩衝區的位置設置標記 1.4
public final Buffer reset() 將此緩衝區的位置重置爲以前標記的位置 1.4
public final Buffer clear() 清除此緩衝區, 即將各個標記恢復到初始狀態,但是數據並沒有真正擦除, 後面操作會覆蓋 1.4
public final Buffer flip() 反轉此緩衝區 1.4
public final Buffer rewind() 重繞此緩衝區 1.4
public final int remaining() 返回當前位置與限制之間的元素數 1.4
public final boolean hasRemaining() 告知在當前位置和限制之間是否有元素 1.4
public abstract boolean isReadOnly() 告知此緩衝區是否爲只讀緩衝區 1.4
public abstract boolean hasArray() 告知此緩衝區是否具有可訪問的底層實現數組 1.6
public abstract Object array() 返回此緩衝區的底層實現數組 1.6
public abstract int arrayOffset() 返回此緩衝區的底層實現數組中第一個緩衝區元素的偏移量 1.6
public abstract boolean isDirect() 告知此緩衝區是否爲直接緩衝區 1.6

從前面可以看出對於 Java 中的基本數據類型(boolean除外),都有一個Buffer類型與之相對應,最常用的自然是ByteBuffer類(二進制數據),該類的主要方法如下:

方法名 描述
public static ByteBuffer allocateDirect(int capacity) 創建直接緩衝區
public static ByteBuffer allocate(int capacity) 設置緩衝區的初始容量
public static ByteBuffer wrap(byte[] array) 把一個數組放到緩衝區中使用
public static ByteBuffer wrap(byte[] array,int offset, int length) 構造初始化位置offset和上界length的緩衝區
public abstract byte get() 從當前位置position上get,get之後,position會自動+1
public abstract byte get (int index) 從絕對位置get
public abstract ByteBuffer put (byte b) 從當前位置上添加,put之後,position會自動+1
public abstract ByteBuffer put (int index, byte b) 從絕對位置上put

Buffer使用示例

public class BasicBuffer {
    public static void main(String[] args) {

        // 創建一個大小爲10的int類型的buffer
        IntBuffer intBuffer = IntBuffer.allocate(10);

        //  向buffer中存放數據
        for (int i = 0; i < 10; i++) {
            intBuffer.put(i);
        }

        // 讀取buffer之前需要進行反轉
        intBuffer.flip();

        // 遍歷buffer,讀取buffer數據
        while (intBuffer.hasRemaining()) {
            System.out.println(intBuffer.get());
        }
    }
}

Buffer使用注意事項

  • ByteBuffer支持類型化的put和get,put放入的是什麼類型,get就應該使用相應的數據類型來取出,否則可能出現BufferUnderflowException異常,如下代碼所示:
public class ByteBufferPutGet {

    public static void main(String[] args) {
        // 創建一個buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(8);

        byteBuffer.putChar('陳');
        byteBuffer.putInt(1);
        byteBuffer.putShort((short) 9);
        // 反轉
        byteBuffer.flip();

//        System.out.println(byteBuffer.getLong());
        System.out.println(byteBuffer.getChar());
        System.out.println(byteBuffer.getInt());
        System.out.println(byteBuffer.getShort());
    }
}
  • 普通buffer設置爲只讀buffer,如果往只讀buffer裏面添加數據則會拋出ReadOnlyBufferException,如下代碼所示:
public class ReadOnlyBuffer {

    public static void main(String[] args) {
        IntBuffer intBuffer = IntBuffer.allocate(8);
        for (int i = 0; i < 8; i++) {
            intBuffer.put(i);
        }

        // 反轉
        intBuffer.flip();

        // 得到一個只讀的buffer
        IntBuffer readOnlyBuffer = intBuffer.asReadOnlyBuffer();
        System.out.println("readOnlyBuffferClass:"+readOnlyBuffer.getClass());

        while (readOnlyBuffer.hasRemaining()) {
            System.out.println(readOnlyBuffer.get());
        }

        readOnlyBuffer.put(99); // 此處會拋出ReadOnlyBufferException
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章