Buffers閱讀筆記
文章目錄
一、簡介
這是一個緩存區的抽象類,真正的數組存儲在ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、CharBuffer、DoubleBuffer、FloatBuffer
二、繼承關係圖
- 由上圖(可以放大)可以看出,Buffer是一個抽象類,有很多子類去實現,但是他們也都是抽象類,但是最終實現的是HeapxxxBuffer。Byte開頭的因爲特殊處理字節,所以會有一個Bits協助
三、存儲結構
- 自身沒有存儲結構,由抽象子類xxxBuffer有一個存儲數組(同類型)
四、源碼分析
內部類
- 無
屬性
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;// 標記,用於reset把position修改爲mark,如果mark=-1或未定義會拋異常
private int position = 0;// 當前位置,表示讀取或寫入的位置
private int limit;// 讀取/寫入的限制,當前索引開始及以後不可讀取和寫入
private int capacity;// 容量。代表該緩存中的容量
static final int SPLITERATOR_CHARACTERISTICS =
Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
long address;
構造
// 初始化構造器,同時初始化核心的4個屬性,注意此構造是採用的默認修飾,所以是不支持直接實例化
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;
}
}
主要方法
1、讀取4大屬性
-
讀取 4 大屬性
public final int capacity() {return capacity;} public final int position() {return position;} public final int limit() {return limit;} // package-private,僅支持同包及本類訪問 final int markValue() {return mark;}
2、單個操作4大屬性
-
單個操作 4 大屬性
/** * capacity 僅在實例化的時候設置 */ /** * 設置position,涉及到邏輯處理 */ public final Buffer position(int newPosition) { // 邊界效驗 if ((newPosition > limit) || (newPosition < 0)) throw new IllegalArgumentException(); // 設置 position = newPosition; // 1. mark 大於 position 直接設置爲-1,reset()就會拋出異常(mark小於0) if (mark > position) mark = -1; return this; } /** * 設置limit,涉及到邏輯處理 */ public final Buffer limit(int newLimit) { // 邊界效驗 if ((newLimit > capacity) || (newLimit < 0)) throw new IllegalArgumentException(); // 設置 limit = newLimit; // 1. position 大於limit,則直接設置position爲limit // 也代表讀寫操作都會拋出異常 if (position > limit) position = limit; // 2. mark 大於 limit直接設置爲-1,reset()就會拋出異常(mark小於0) if (mark > limit) mark = -1; return this; } /** * 設置mark,在當前位置(position)設置標記 */ public final Buffer mark() { mark = position; return this; }
3、緩衝區4屬性處理
-
緩衝區屬性處理
/** * 還原緩衝區的數據 * 還原一切狀態 */ 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; } /** * 反轉此緩衝區 * 適合用於在緩衝區寫入數據,然後,再從緩衝區讀取數據(不用考慮limit限制) * 也就是使緩衝區爲“重新讀取”已包含的數據做好準備,他使限制保持不變,講位置設置爲0 * 類似substring截取 */ public final Buffer flip() { limit = position; position = 0; mark = -1; return this; } /** * 重繞緩衝區,將當前位置設置爲0,並丟棄標記 * 適合用於重新讀取/寫入緩衝區時,(前提是設置了適當的limit限制) * 重新讀取重新吸入的時候可用 */ public final Buffer rewind() { position = 0; mark = -1; return this; }
4、判斷剩餘量和底層數組
-
判斷剩餘量和底層數組
/** * 判斷是否還有剩餘可讀寫容量 */ public final boolean hasRemaining() { return position < limit; } /** * 抽象方法:是否是隻讀(非直接緩存(JVM中間緩存區)支持讀寫,但是直接緩存(內存)只支持讀) */ public abstract boolean isReadOnly(); /** * 抽象方法:JVM緩衝區是否有數組 */ public abstract boolean hasArray(); /** * 抽象方法:是否是直接緩存區(直接跳過JVM中間緩存區) */ public abstract boolean isDirect();
5、獲取剩餘容量和底層數組
-
獲取剩餘容量和底層數組
/** * 獲得剩餘可讀寫的容量 */ public final int remaining() { return limit - position; } /** * 抽象方法,獲取數組 */ public abstract Object array(); /** * 獲取數組的偏移量 */ public abstract int arrayOffset();
6、其他package-private可用方法
-
其他默認修飾方法
/** * 所有子類get使用,使當前位置(position)+ 1,並返回原position索引 */ final int nextGetIndex() { // package-private if (position >= limit) throw new BufferUnderflowException(); return position++; } /** * 所有子類get使用,使當前位置(position)+ nb,並返回原position索引 */ final int nextGetIndex(int nb) { // package-private if (limit - position < nb) throw new BufferUnderflowException(); int p = position; position += nb; return p; } /** * 同get一樣邏輯 * 所有子類put使用,使當前位置(position)+ 1,並返回原position索引 */ final int nextPutIndex() { // package-private if (position >= limit) throw new BufferOverflowException(); return position++; } /** * 同get一樣邏輯 * 所有子類put使用,使當前位置(position)+ nb,並返回原position索引 */ final int nextPutIndex(int nb) { // package-private if (limit - position < nb) throw new BufferOverflowException(); int p = position; position += nb; return p; } /** * 檢查 i 是否可讀寫 */ final int checkIndex(int i) { // package-private if ((i < 0) || (i >= limit)) throw new IndexOutOfBoundsException(); return i; } /** * 檢查 i 是否可讀寫,nb代表每次讀寫的位,一次讀寫的位超出limit則邊界異常 */ final int checkIndex(int i, int nb) { // package-private if ((i < 0) || (nb > limit - i)) throw new IndexOutOfBoundsException(); return i; } /** * 讀取當前mark值 */ final int markValue() { // package-private return mark; } /** * 限制讀寫操作,直接所有設置最低值 */ final void truncate() { // package-private mark = -1; position = 0; limit = 0; capacity = 0; } /** * 丟棄原mark,直接設置爲-1 */ final void discardMark() { // package-private mark = -1; } /** * off 開始索引位 * len 每次讀寫操作量 * size 此數組容量長度 * 效驗本次讀取是否超出邊界 */ static void checkBounds(int off, int len, int size) { // package-private if ((off | len | (off + len) | (size - (off + len))) < 0) throw new IndexOutOfBoundsException(); }
補充
五、總結
抽象類 ShortBuffer、LongBuffer、IntBuffer、DoubleBuffer、FloatBuffer的所有函數基本上是一樣的,只是存儲的接口不同。所以操作有點卻別,但是函數一樣。
charBuffer由於需要操作字符,所以比上面的會多一些例如append,charAt、subDequence函數
ByteBuffer因爲也比上面多,例如_get、_put、putXXX、getXXX、asXXXBuffer等
heapXXXBuffer的實現類同上,也是相似和不同之處。原因請看後面的源碼分析