Java NIO深入(Buffer)-我們到底能走多遠系列(18)


我們到底能走多遠系列(18)

扯淡:最近想要跳槽,現公司的主管不高興,沒提的時候關系好像很好,提的時候我比較堅決,他硬要我留一個月,老實說我想弄個三周就好了,對,國際慣例一個月,我也是想砍個一周下來休息下,他居然恐嚇我,表達出我不仁他就不義的態度,表示可以再沒走的時候為難我。現在開始挑我工作毛病了,態度已經不行了,有點裝不住了,哈哈。我想,你這么搞我,我交接也不會盡全力了的,做到本職就滾蛋,留下的坑,你們慢慢填。

  最近一個月,經歷了些事情,又教育了我一邊,要投資自己,讓自己變強,才能在有風雨時不倒。僥幸想在別人的樹下躲避風雨的,今天可能過了關,包不好明天能不能過。我覺得,不要受制於人的要求是有點高,能做到不完全受制於人已經不錯了。

主題:

關於NIO的基本知識在(系列17)記錄過了,繼續來了解下Buffer

Buffer API:

int capacity()//返回此緩沖區的容量。 
Buffer clear()//清除此緩沖區。 
Buffer flip()//反轉此緩沖區。 
boolean hasRemaining()//判斷在當前位置和限制之間是否有任何元素。 
abstract  boolean isReadOnly()//判斷此緩沖區是否為只讀緩沖區。 
int limit()//返回此緩沖區的限制。 
Buffer limit(int newLimit)//設置此緩沖區的限制。 
Buffer mark()//在此緩沖區的位置設置其標記。 
int position()//返回此緩沖區的位置。 
Buffer position(int newPosition)//設置此緩沖區的位置。 
int remaining()//返回當前位置與限制之間的元素數量。 
Buffer reset()//將此緩沖區的位置重新設置成以前標記的位置。 
Buffer rewind()//重繞此緩沖區。

直接看源碼,關於其中的flip和clear方法在系列17中詳細學習了。

public abstract class Buffer {

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;    // 一個備忘位置
    private int position = 0; // 位置,下一個要被讀或寫的元素的索引,根據它來決定讀哪個位置
    private int limit; // 上界,緩沖區的第一個不能被讀或寫的元素。
    private int capacity; // 緩沖區容量。緩沖區創建時被設定,並且永遠不能被改變。

    // 初始化
    Buffer(int mark, int pos, int lim, int cap) {    // package-private
    if (cap < 0)
        throw new IllegalArgumentException();
    this.capacity = cap;
    limit(lim);
    position(pos);
    if (mark >= 0) {
        if (mark > pos)
        throw new IllegalArgumentException();
        this.mark = mark;
    }
    }
    
    public final int capacity() {
    return capacity;
    }

    public final int position() {
    return position;
    }

    public final Buffer position(int newPosition) {
    if ((newPosition > limit) || (newPosition < 0))
        throw new IllegalArgumentException();
    position = newPosition;
    if (mark > position) mark = -1; // 因為重新設置position,mark可能超過它,索性把mark還原
    // 返回設置好后新的自己
    // 這種返回自己的方式可以實現支持級聯調用,比如buffer.mark().position(5).reset( );
    return this; 
    }

    public final int limit() {
    return limit;
    }

    public final Buffer limit(int newLimit) {
    if ((newLimit > capacity) || (newLimit < 0))
        throw new IllegalArgumentException();
    limit = newLimit;
    // limit的設置牽涉到下面兩個:position和mark
    if (position > limit) position = limit;
    if (mark > limit) mark = -1;
    return this;
    }

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

    public final Buffer reset() {
        int m = mark;
    if (m < 0)
        throw new InvalidMarkException();
    position = m;// 把position設置到mark的位置,下一次讀數據的時候就可以,從mark的位置讀起了。
    return this;
    }

    public final Buffer clear() {
    position = 0; // position清零
    limit = capacity; // limit初始化
    mark = -1; // mark初始化
    // 三步操作這個Buffer又重生了。可以繼續用了。下一次寫入,就是覆蓋即可。
    // 注意clear方法返回了自己,因為clear方法沒有真正意義上clear自己的內容,如果這時候我們操作返回的buffer,這個buffer是有內容的。
    return this; 
    }

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

    public final Buffer rewind() {
    position = 0;// 和clear()操作不同的是少了limit初始化,如此即可實現對這個buffer的重讀
    mark = -1;
    return this;
    }
    //返回當前位置與限制之間的元素數量。
    public final int remaining() {
    return limit - position;
    }
    //判斷在當前位置和限制之間是否有任何元素。 
    public final boolean hasRemaining() {
    return position < limit;
    }
    // 所有的緩沖區都是可讀的,但並非所有都可寫。
    public abstract boolean isReadOnly();
    // 后面還有nextGetIndex(),nextGetIndex(int nb) 等方法,因為是不是對外提供的方法,就不進一步介紹了。
}

ByteBuffer的API:

1,HeapByteBuffer中實現了抽象類ByteBuffer中為實現的方法。

2,ByteBuffer中的get set 方法就是對一個數組的操作。

get的四個方法:

get();
get (int index);
get(byte[] dst);
get(byte[] dst, int offset, int length);

前兩個方法比較好理解,返回的是取得的內容,后面兩個方法是將此緩沖區的字節傳輸到給定的目標數組中。

來看下源碼:

public ByteBuffer get(byte[] dst) {
    return get(dst, 0, dst.length);
}
    
public ByteBuffer get(byte[] dst, int offset, int length) {
    checkBounds(offset, length, dst.length);
    if (length > remaining())
        throw new BufferUnderflowException();
    int end = offset + length;
    // 最后還是一個個拿
    for (int i = offset; i < end; i++)
        dst[i] = get();
    return this;
}

put方法API:

abstract  ByteBuffer put(byte b)
ByteBuffer put(byte[] src)
ByteBuffer put(byte[] src, int offset, int length)
ByteBuffer put(ByteBuffer src)
abstract  ByteBuffer put(int index, byte b)

 

壓縮方法:

public abstract ByteBuffer compact( );

看下圖,使用前:

使用后:

調用compact()的作用是丟棄已經釋放的數據,保留未釋放的數據,並使緩沖區對重新填充容量准備就緒。但是需要注意的時候如果我們需要馬上讀取數據的時候還是需要先調用flip()方法,把position置0。

 

有點發燒,預計的內容寫不上去,先停一下,下次補上去。

 

讓我們繼續前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不會成功。
共勉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM