緩衝區Buffer

緩衝區介紹

abstract class Buffer
7個直接子類
abstract class ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer。
NIO中的Buffer是一個用於存儲腳本數據類型的容器,以類似於數組有序的方式來存儲和組織數據。

Buffer類的使用

API:
在這裏插入圖片描述

包裝數據與獲得容量

	//Invariants: mark <= position <= limit <= capacity
	private int mark = -1; //標記
    private int position = 0; //位置
    private int limit; //限制
    private int capacity; //容量

Buffer的7個子類也是抽象的,不能通過new 實例化,使用靜態方法wrap()實現。wrap方法將數組放入緩衝區,來構建存儲不同數據類型的緩衝區。

	byte[] byteArray = new byte[]{1,2,3};
    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
    System.out.println(byteBuffer.getClass().getName());
    System.out.println(byteBuffer.capacity());

output:
	java.nio.HeapByteBuffer
	3

wrap源碼

  /**
     * Wraps a byte array into a buffer.
     *
     * <p> The new buffer will be backed by the given byte array;
     * that is, modifications to the buffer will cause the array to be modified
     * and vice versa.  The new buffer's capacity and limit will be
     * <tt>array.length</tt>, its position will be zero, and its mark will be
     * undefined.  Its {@link #array backing array} will be the
     * given array, and its {@link #arrayOffset array offset>} will
     * be zero.  </p>……
     */
    public static ByteBuffer wrap(byte[] array) {
        return wrap(array, 0, array.length);
    }
    /**……
     *
     * @param  array
     *         The array that will back the new buffer
     * @param  offset
     *         The offset of the subarray to be used; must be non-negative and
     *         no larger than <tt>array.length</tt>.  The new buffer's position
     *         will be set to this value.
     * @param  length
     *         The length of the subarray to be used;
     *         must be non-negative and no larger than
     *         <tt>array.length - offset</tt>.
     *         The new buffer's limit will be set to <tt>offset + length</tt>.
     * @return  The new byte buffer
     */
    public static ByteBuffer wrap(byte[] array,int offset, int length){
        try {
            return new HeapByteBuffer(array, offset, length);
        } catch (IllegalArgumentException x) {
            throw new IndexOutOfBoundsException();
        }
    }

ByteBuffer類緩衝區的原理是使用byte[]數組進行數據的保存,在後續使用指定的API來操作這個數組已達到操作緩衝區的目的。

	HeapByteBuffer(byte[] buf, int off, int len) { // package-private
        super(-1, off, off + len, buf.length, buf, 0);
    }

	ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset){
        super(mark, pos, lim, cap);
        this.hb = hb;
        this.offset = offset;
    }

從源碼可以看到,緩衝區存儲的數據還是存儲在byte[]字節數組中。使用緩衝區與使用byte[]字節數組的優點在於緩衝區將存儲數據的byte[]字節數組內容與相關的信息整合在一個Buffer類中,將數據與緩衝區中的信息進行了整合並封裝,便於獲得相關的信息及處理數據。

限制獲取與設置

限制代表第一個不應該讀取或寫入元素的index

limit源碼:

	/**
     * Returns this buffer's limit.
     */
    public final int limit() {
        return limit;
    }
	/**
     * Sets this buffer's limit.  If the position is larger than the new limit
     * then it is set to the new limit.  If the mark is defined and larger than
     * the new limit then it is discarded.
     *
     * @param  newLimit
     *         The new limit value; must be non-negative
     *         and no larger than this buffer's capacity
     *
     * @return  This buffer
     *
     * @throws  IllegalArgumentException
     *          If the preconditions on <tt>newLimit</tt> do not hold
     */
    public final Buffer limit(int newLimit) {
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        limit = newLimit;
        if (position > limit) position = limit;
        if (mark > limit) mark = -1;
        return this;
    }

示例

		char[] charArr = new char[]{'a','b','c','d','e','f'};
        CharBuffer charBuffer = CharBuffer.wrap(charArr);
        System.out.println("capacity = " + charBuffer.capacity() + " limit=" + charBuffer.limit());
        
        charBuffer.limit(3);
        System.out.println("capacity = " + charBuffer.capacity() + " limit=" + charBuffer.limit());
        
        charBuffer.put(0,'h');
        charBuffer.put(1,'i');
        charBuffer.put(2,'j');
        charBuffer.put(3,'k');  //第一個不可讀不可寫的索引
        charBuffer.put(4,'l');
output:
	capacity = 6 limit=6
	capacity = 6 limit=3
	java.lang.IndexOutOfBoundsException
		……

Limit的使用場景是當反覆向緩衝區中存儲數據時使用,如第一次向緩衝區寫入 A到G 7個字符,然後全部讀取,第二次向緩衝區寫入1到4 4個字符,如果讀取到1、2、3、4、E、F、G是錯誤的,需要結合limit限制讀取範圍。

位置獲取與設置

源碼

/**
     * Returns this buffer's position.
     *
     * @return  The position of this buffer
     */
    public final int position() {
        return position;
    }

    /**
     * Sets this buffer's position.  If the mark is defined and larger than the
     * new position then it is discarded.
     *
     * @param  newPosition
     *         The new position value; must be non-negative
     *         and no larger than the current limit
     *
     * @return  This buffer
     *
     * @throws  IllegalArgumentException
     *          If the preconditions on <tt>newPosition</tt> do not hold
     */
    public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }

剩餘空間大小獲取

返回當前位置與limit之間的元素數

/**
     * Returns the number of elements between the current position and the
     * limit.
     *
     * @return  The number of elements remaining in this buffer
     */
    public final int remaining() {
        return limit - position;
    }
    ```

## 使用Buffer mark()方法處理標記
緩衝區的 標記是一個索引,在調用reset()方法時,會將緩衝區的position位置重置爲該索引。標記mark並不是必須的。定義mark時,不能將其定義爲負數,並且不能讓他大於position。如果定義了mark,則在將position或limit調整爲小於該mark的值時,該mark將被丟棄,丟棄後的mark值是-1.如果未定義mark,那麼調用reset方法將導致拋出invalidMarkException。

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