Buffer
簡介Buffer
的核心屬性Buffer
的建立與使用(ByteBuffer
爲例)緩衝區(Buffer
):本質上是一個數組,用於臨時保存、寫入以及讀取數據。在Java NIO
中,
該內存塊包含在NIO Buffer
對象當中,NIO Buffer
對象還提供了一組接口來訪問該內存塊。java
根據數據類型的不一樣,Java
爲除了boolean
類型以外的其他7種基本類型提供了相應類型的緩衝區,
分別是ByteBuffer
、CharBuffer
、ShortBuffer
、IntBuffer
、LongBuffer
、
FloatBuffer
、DoubleBuffer
。他們都繼承自抽象類Buffer
類,他們的管理方式也都幾乎同樣。
UML
類圖以下:
數組
BUffer
類的部分實現以下:安全
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("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; } } /** * Returns this buffer's capacity. * * @return The capacity of this buffer */ //返回這個Buffer的容量 public final int capacity() { return capacity; } /** * Returns this buffer's position. * * @return The position of this buffer */ //返回這個Buffer中當前的位置(當前操做數) public final int position() { return position; } /** * Returns this buffer's limit. * * @return The limit of this buffer */ //返回當前Buffer中能夠被操做的元素的個數 public final int limit() { return limit; } /** * Sets this buffer's mark at its position. * * @return This buffer */ //記錄當前position的位置 public final Buffer mark() { mark = position; return this; } public final Buffer reset() { int m = mark; if (m < 0) throw new InvalidMarkException(); position = m; return this; } }
其中定義了四個Buffer
屬性,對應的描述以下app
屬性 | 描述 |
---|---|
capacity | 容量;用於描述這個Buffer大小,即建立的數組的長度,一旦聲明不能夠被改變 |
position | 位置,表示當前緩衝區中正在操做的數據的位置,在切換讀取時會將其置0 |
limit | 界限、限制;表示當前緩衝區中能夠操做的數據的大小,默認狀況下爲Buffer的大小,切換爲讀取模式後爲數組中元素的個數(準確的說時切換以前position的值) |
mark | 標記;用於記錄當前position的位置,後續操做過程當中可使用reset()方法將position還原至最後一次mark的位置 |
在Java NIO
中可使用對應Buffer
類的allocate()
或者allocateDirect()
靜態方法建立。性能
//使用allocate()建立 ByteBuffer byteBuffer=ByteBuffer.allocate(1024); //使用allocateDirect()建立 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
而Buffer
的本質是一個數組,建立時須要指定數組的大小this
Buffer
的使用通常分爲四個步驟spa
Buffer
中寫入數據Buffer
切換爲讀取模式Buffer
Buffer
清空,供後續寫入使用1. 寫如數據操作系統
//使用put()方法向Buffer中寫入數據 byteBuffer.put("bmilk".getBytes()); //使用Channel#read()向Buffer中寫入數據 channel.read(byteBuffer);
2. 將Buffer
切換爲讀取模式指針
能夠經過調用flip()
方法將Buffer
從寫模式切換到讀模式。code
byteBuffer.flip()
調用flip()
方法會將position
設回0,並將limit
設置成以前position
的值。
即,如今使用position
標記讀的位置,limit
表示以前寫進了多少個byte
,也就是如今
能讀取多少個byte
等。
3. 讀取Buffer
讀取Buffer
有兩種方式:
Buffer
種讀取數據到Channel
get()
方法從Buffer
種讀取數據//從Buffe中將數據寫入通道 inChannel.write(byteBuffer) //使用get()方法從BUffer中讀取數據 byte[] bytes=new byte[byteBuffer.limit()]; byteBuffer.get(bytes);
4. 將Buffer
清空,供後續寫入使用
使用clear()
清空緩衝區,清空緩衝區只是使各個指針恢復初始位置,
更具體的說是position
設置爲0,limit
設置爲容量的初始大小。
並不會真實清空其中數據,可是能夠經過後續的寫覆蓋以前的數據
byteBuffer.clear()
rewind()
從Buffer
重複讀取數據//使用`rewind()`從`Buffer`重複讀取數據 //Buffer.rewind()將position設回0,因此你能夠重讀Buffer中的全部數據。 //limit保持不變,仍然表示能從Buffer中讀取多少個元素(byte、char等)。 Buffer rewind = byteBuffer.rewind();
compact()
方法clear()
會使使各個指針恢復初始位置,可是實際中可能存在部分數據尚未被使用,然後續須要使用。
又必須清理一部分Buffer
的空間,compact()
方法會將全部未讀數據拷貝到Buffer的起始處,
而後將position
指針設置到最後一個未讀元素的後面,如今Buffer
能夠進行寫數據,
可是不會覆蓋前面的未讀的數據。
mark()
方法與reset()
方法經過調用Buffer.mark()方法,能夠標記Buffer中的當前的position。以後能夠經過調用Buffer.reset()方法恢復到這個position。
//使用mark標記當前的position位置 byteBUffer.mark() //使用reset方法使position指針返回這個位置 byteBuffer.reset()
4.equals()
方法與compareTo()
方法
當須要比較兩個Buffer
時可使用equals()
方法與compareTo()
方法。
equals()
方法判斷兩個方式是否相等,當知足下列條件時,表示兩個Buffer
相等
- 有相同的類型(
byte
、char
、int
等)Buffer
中剩餘的byte
、char
等的個數相等。- \(\color{#FF3030}{`Buffer`中全部剩餘的`byte`、`char`等都相同}\)
compareTo()
方法比較兩個兩個Buffer
的大小,僅比較剩餘元素(byte
、char
等)
若是知足下列條件,則認爲一個Buffer
「小於」另外一個Buffer
:
- 第一個不相等的元素小於另外一個Buffer中對應的元素
- 全部元素都相等,但第一個Buffer比另外一個先耗盡(第一個Buffer的元素個數比另外一個少)。
allocate()
方法分配緩衝區,將緩衝區創建在JVM內存中allocateDirect()
方法分配直接緩衝區,將緩衝區創建在物理內存中,能夠在某些狀況下提升效率直接緩衝區(物理內存映射文件):相比非直接緩衝區省略了copy
的過程,因此說直接緩區能夠必定程度上提升效率
弊端:
java
程序將數據寫入物理內存映射文件中,以後數據將不受Java
程序控制,java
虛擬機會見最大努力直接在此緩衝區上執行本機I/O
。I/O
以前或以後,虛擬機都回儘可能避免將緩衝區的內容複製到中間緩衝區或者從中間緩衝區中複製內容。allocateDirect()
工廠方法來建立,FileChannel
的map()
方法,將文件區域直接映射到內存中來建立,MappedByteBuffer
。Java
的實現有助於JNI
從本地及代碼建立直接字節緩衝區,isDirect()
方法來肯定,提供此方法是爲了可以在性能關鍵型代碼中執行顯式緩衝區管理。本文簡單介紹了Buffer
的種類,並對經常使用方法進行樂簡單的介紹