Buffer是一個包裝了基本數(shù)據(jù)元素數(shù)組的對象,它以及它的子類定義了一系列API用于處理數(shù)據(jù)緩存。

一、屬性
Buffer有四個基本屬性:
1、capacity 容量,buffer能夠容納的最大元素數(shù)目,在Buffer創(chuàng)建時設(shè)定并不能更改
2、limit buffer中有效位置數(shù)目
3、position 下一個讀或者寫的位置
4、mark 用于記憶的標(biāo)志位,配合reset()使用,初始值未設(shè)定,調(diào)用mark后將當(dāng)前position設(shè)為值
四者關(guān)系:0 <= mark <= position <= limit <= capacity
二、API
支持鏈?zhǔn)秸{(diào)用,如:buffer.mark().position(5).reset( );
注意isReadOnly()方法決定了buffer是否可寫。
三、操作
以ByteBuffer為例,
1、訪問,通過get(),get(index),其中g(shù)et()從當(dāng)前position位置讀取,get(index)從index位置讀取,不改變當(dāng)前position,下面要說到的put也一樣。
2、填充,通過put(byte),put(index,byte),按照絕對位置填充也是不改變當(dāng)前position屬性
3、flipping,試想,我們將填充完畢的buffer傳遞給socket輸出,那么socket讀取是依據(jù)position屬性確定,就會從結(jié)尾后一位開始讀,這樣肯定是不正確的,如果要正確的讀取我們先要:
buffer.limit(buffer.position( )).position(0);
將limit設(shè)為position, 將position設(shè)為0,這個操作就叫flipping,API直接提供了這個操作:
buffer.flip( );
特別注意,flip()方法會改變limit屬性,將limit屬性從capacity設(shè)置為當(dāng)前position。rewind()方法與flip()類似,但是僅將position設(shè)為0,而不改變limit,通常用于重新讀取已經(jīng)被flip的buffer。flip()另一個注意點是,兩次調(diào)用buffer的flip方法,將使得position和limit屬性都為0。
4、迭代取元素:
5.clear()方法,將buffer重設(shè)為空狀態(tài),也就是設(shè)置limit=capacity,position=0,以便重復(fù)利用。
6.compact()方法,用于壓縮buffer,這個方法在多次重復(fù)調(diào)用時是比較低效。
7.mark(),初始是未定義的,這適合如果調(diào)用reset將拋出InvalidMarkException。調(diào)用makr()后,將當(dāng)前position設(shè)為mark以便reset時返回。注意,rewind( ), clear( ), and flip( )方法都將丟棄已經(jīng)創(chuàng)建的mark。調(diào)用limit(index),positioon(index),如果index的值小于當(dāng)前mark,mark也將被丟棄。
8.比較,可以通過equals()和compateTo()方法來比較兩個buffer,前一個返回boolean,后一個返回0,-1,1。兩個buffer equal的條件是:
1)類型相同
2)剩余元素的數(shù)目相等
3)剩余元素也一一相等
9、批量移動數(shù)據(jù),為了更有效地進行數(shù)據(jù)傳送,批量的數(shù)據(jù)存取肯定是不能少的,Buffer及其子類都有提供類似的方法,比如CharBuffer:
四、創(chuàng)建Buffer
Buffer以及其子類都無法直接new,而必須把通過他們提供的工廠方法來創(chuàng)建。通常有兩種方式:
1、allocate,例如
CharBuffer charBuffer = CharBuffer.allocate (100);
將在堆上分配一個可以存儲100個字符的數(shù)組作為backing store。
2、wrap,包裝一個已有的數(shù)組:
char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
注意,這樣的方式創(chuàng)建的Buffer,將不會在堆上創(chuàng)建新的數(shù)組,而是直接利用myArray做backing store,這意味著任何對myArray或者buffer的修改都將影響到buffer或者myArray??梢酝ㄟ^public final boolean hasArray( )方法來判斷是否擁有一個數(shù)組,通過array()方法取得這個數(shù)組。
五、復(fù)制Buffer
其實這個復(fù)制也是“淺拷貝”,通過duplicate()方法將返回一個新創(chuàng)建的buffer,這個新buffer與原來的Buffer共享數(shù)據(jù),一樣的capacity,但是有自己的position、limit和mark屬性。通過asReadOnlyBuffer()方法復(fù)制的buffer與duplicate()類似,但是是只讀的,不能調(diào)用put。比較特別的是slice()方法,故名思議,類似切割一個Buffer出來,與duplicate類似,但是它將從原來Buffer的當(dāng)前position開始,并且capacity等于原來Buffer的剩余元素數(shù)目,也就是(limit-position)。
一、屬性
Buffer有四個基本屬性:
1、capacity 容量,buffer能夠容納的最大元素數(shù)目,在Buffer創(chuàng)建時設(shè)定并不能更改
2、limit buffer中有效位置數(shù)目
3、position 下一個讀或者寫的位置
4、mark 用于記憶的標(biāo)志位,配合reset()使用,初始值未設(shè)定,調(diào)用mark后將當(dāng)前position設(shè)為值
四者關(guān)系:0 <= mark <= position <= limit <= capacity
二、API
package java.nio;
public abstract class Buffer {
public final int capacity( )
public final int position( )
public final Buffer position (int newPosition)
public final int limit( )
public final Buffer limit (int newLimit)
public final Buffer mark( )
public final Buffer reset( )
public final Buffer clear( )
public final Buffer flip( )
public final Buffer rewind( )
public final int remaining( )
public final boolean hasRemaining( )
public abstract boolean isReadOnly( );
}
public abstract class Buffer {
public final int capacity( )
public final int position( )
public final Buffer position (int newPosition)
public final int limit( )
public final Buffer limit (int newLimit)
public final Buffer mark( )
public final Buffer reset( )
public final Buffer clear( )
public final Buffer flip( )
public final Buffer rewind( )
public final int remaining( )
public final boolean hasRemaining( )
public abstract boolean isReadOnly( );
}
支持鏈?zhǔn)秸{(diào)用,如:buffer.mark().position(5).reset( );
注意isReadOnly()方法決定了buffer是否可寫。
三、操作
以ByteBuffer為例,
1、訪問,通過get(),get(index),其中g(shù)et()從當(dāng)前position位置讀取,get(index)從index位置讀取,不改變當(dāng)前position,下面要說到的put也一樣。
2、填充,通過put(byte),put(index,byte),按照絕對位置填充也是不改變當(dāng)前position屬性
3、flipping,試想,我們將填充完畢的buffer傳遞給socket輸出,那么socket讀取是依據(jù)position屬性確定,就會從結(jié)尾后一位開始讀,這樣肯定是不正確的,如果要正確的讀取我們先要:
buffer.limit(buffer.position( )).position(0);
將limit設(shè)為position, 將position設(shè)為0,這個操作就叫flipping,API直接提供了這個操作:
buffer.flip( );
特別注意,flip()方法會改變limit屬性,將limit屬性從capacity設(shè)置為當(dāng)前position。rewind()方法與flip()類似,但是僅將position設(shè)為0,而不改變limit,通常用于重新讀取已經(jīng)被flip的buffer。flip()另一個注意點是,兩次調(diào)用buffer的flip方法,將使得position和limit屬性都為0。
4、迭代取元素:
for (int i = 0; buffer.hasRemaining( ), i++) {
myByteArray [i] = buffer.get( );
}
int count = buffer.remaining( );
for (int i = 0; i < count, i++) {
myByteArray [i] = buffer.get( );
}
ByteBuffer不是線程安全的,前一種方式適合并發(fā)訪問,后一種方式效率更高。這兩種方式都是一個一個取,效率都比批量取低。myByteArray [i] = buffer.get( );
}
int count = buffer.remaining( );
for (int i = 0; i < count, i++) {
myByteArray [i] = buffer.get( );
}
5.clear()方法,將buffer重設(shè)為空狀態(tài),也就是設(shè)置limit=capacity,position=0,以便重復(fù)利用。
6.compact()方法,用于壓縮buffer,這個方法在多次重復(fù)調(diào)用時是比較低效。
7.mark(),初始是未定義的,這適合如果調(diào)用reset將拋出InvalidMarkException。調(diào)用makr()后,將當(dāng)前position設(shè)為mark以便reset時返回。注意,rewind( ), clear( ), and flip( )方法都將丟棄已經(jīng)創(chuàng)建的mark。調(diào)用limit(index),positioon(index),如果index的值小于當(dāng)前mark,mark也將被丟棄。
8.比較,可以通過equals()和compateTo()方法來比較兩個buffer,前一個返回boolean,后一個返回0,-1,1。兩個buffer equal的條件是:
1)類型相同
2)剩余元素的數(shù)目相等
3)剩余元素也一一相等
9、批量移動數(shù)據(jù),為了更有效地進行數(shù)據(jù)傳送,批量的數(shù)據(jù)存取肯定是不能少的,Buffer及其子類都有提供類似的方法,比如CharBuffer:
public CharBuffer get (char [] dst)
public CharBuffer get (char [] dst, int offset, int length)
public final CharBuffer put (char[] src)
public CharBuffer put (char [] src, int offset, int length)
public CharBuffer put (CharBuffer src)
public final CharBuffer put (String src)
public CharBuffer put (String src, int start, int end)
public CharBuffer get (char [] dst, int offset, int length)
public final CharBuffer put (char[] src)
public CharBuffer put (char [] src, int offset, int length)
public CharBuffer put (CharBuffer src)
public final CharBuffer put (String src)
public CharBuffer put (String src, int start, int end)
四、創(chuàng)建Buffer
Buffer以及其子類都無法直接new,而必須把通過他們提供的工廠方法來創(chuàng)建。通常有兩種方式:
1、allocate,例如
CharBuffer charBuffer = CharBuffer.allocate (100);
將在堆上分配一個可以存儲100個字符的數(shù)組作為backing store。
2、wrap,包裝一個已有的數(shù)組:
char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
注意,這樣的方式創(chuàng)建的Buffer,將不會在堆上創(chuàng)建新的數(shù)組,而是直接利用myArray做backing store,這意味著任何對myArray或者buffer的修改都將影響到buffer或者myArray??梢酝ㄟ^public final boolean hasArray( )方法來判斷是否擁有一個數(shù)組,通過array()方法取得這個數(shù)組。
五、復(fù)制Buffer
其實這個復(fù)制也是“淺拷貝”,通過duplicate()方法將返回一個新創(chuàng)建的buffer,這個新buffer與原來的Buffer共享數(shù)據(jù),一樣的capacity,但是有自己的position、limit和mark屬性。通過asReadOnlyBuffer()方法復(fù)制的buffer與duplicate()類似,但是是只讀的,不能調(diào)用put。比較特別的是slice()方法,故名思議,類似切割一個Buffer出來,與duplicate類似,但是它將從原來Buffer的當(dāng)前position開始,并且capacity等于原來Buffer的剩余元素數(shù)目,也就是(limit-position)。