緩衝區介紹
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。