NIO 源碼基礎篇 - buffer

一 NIO 是非阻塞,主要是Channel , Selector, Buffer ,我們來學習下Buffer,此圖不全。

 

發現buffer,java 實現了除了boolean 類型的其他的7中基礎數據類型。

Buffer 是指一個存放基元類型的數據容器。

如何定義一個Buffer。

     從構造函數的參數可以看出,需要傳遞4個參數。

    mark:標記的位置,重新標記讀寫的position位置。

    pos: 緩存下一個將要讀取或或寫的位置。

    lim:  限制寫入或讀取的長度大小

    cap: 表示初始化後buffer對象的長度。

 Buffer(int mark, int pos, int lim, int cap) {       // package-private
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("
                                                   + mark + " > " + pos + ")");
            this.mark = mark;
        }
    }

  在構造函數中對lim / pos 進行了預判。

 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;
    }

     首先 limit 限制必須滿足小於capacity的限制,而且不能爲負數,不然會拋出異常。

     如果當前的position大於limit的限制,則把position值進行負值給limit。

     前文說了mark是標記position的位置的,如果mark大於limit的話,怎丟棄標誌mark,-1 表示丟棄。

 public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }

  對position位置的檢測,position 不能大於limit ,而且不能爲負數,否則拋出異常。

  同時mark如果大於position了,則被丟棄。這裏你是否有疑問,mark的值是有position復值,怎麼會和position不一致呢。查看    源碼,代碼裏確實如此,不過初始化的時候,需要做mark校驗檢查的。

 public final Buffer mark() {
        mark = position;
        return this;
    }

  -1 表示丟棄?

 final void discardMark() {                          // package-private
        mark = -1;
    }

 buffer的作用是用來進行讀寫數據,數據不是write 就 read.

   /** <blockquote><pre>
     * buf.put(magic);    // Prepend header
     * in.read(buf);      // Read data into rest of buffer
     * buf.flip();        // Flip buffer
     * out.write(buf);    // Write header + data to channel</pre></blockquote>
     */

  public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

   /** <blockquote><pre>
     * out.write(buf);    // Write remaining data
     * buf.rewind();      // Rewind buffer
     * buf.get(array);    // Copy data into array</pre></blockquote>
     *
     * @return  This buffer
     */

 public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

 這個兩個方法都可以用與buffer的讀取狀態切換,哪有什麼區別的,flip() 比 rewind 多了一行代碼。

rewind 每次操作都是buffer的全部數據假設limit=cap。 而flip是有限制的。

還有一寫輔助操作buffer 的輔助方法。

  剩餘未操作的數據大小

public final int remaining() {
        return limit - position;
    }

判斷是否可操作

 public final boolean hasRemaining() {
        return position < limit;
    }

清除並不是真正的清除數據,是改變position值和限制大小,如何避免多讀取數據呢,關鍵在於limit 的值=position,如果數據操作了。就做限制,讀取數據就不會出錯。

  public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }
 public final Buffer reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }

重設只是改變position的值設置爲mark,在mark位置進行重新的操作。

以上的操作並沒有真正清除數據,只是進行數據的覆蓋。

邊界檢查

static void checkBounds(int off, int len, int size) { // package-private
        if ((off | len | (off + len) | (size - (off + len))) < 0)
            throw new IndexOutOfBoundsException();
    }

off: 開始索引

len:操作的數組長度

size: 數組的大小

'||' 表示只要一個滿足都滿足,不再進行其他檢查判斷。

‘|’ 表示按位或, 負數|任何數都是負數。

總結:

             Buffer 是 NIO出現的類,在做數據的序列化 傳輸上使用。

             Buffer 使用前必須指定大小,這個空間後期不會改變,是設計的一方面的缺陷吧。

           

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