ByteBuffer详解(大概2333)
ByteBuffer詳解
- ByteBuffer詳解
- 概述
- ByteBuffer屬性
- capacity
- limit
- position
- Mark
- ByteBuffer方法
- allocate()
- order()
- put()
- flip()
- array()
- get()
- wrap()
- clear()
- rewind()
- campact()
- 最后
概述
ByteBuffer顧名思義就是byte緩沖區,實際上底層就是byte[ ]。ByteBuffer有兩種,一種是HeapByteBuffer,還有一種是DirectByteBuffer。我們知道ByteBuffer實際就是一塊內存,前者是屬于JVM的內存,后者則是申請的JVM以外的內存,也就是運行JVM的系統的內存。沒有特殊需求一般都是用HeapByteBuffer吧(大概,畢竟我也沒工作,不知道大佬們的世界)。
ByteBuffer屬性
capacity
容量(capacity),由我們根據需要指定,也就是這個ByteBuffer在內存中分配的(也即是可使用的最大)空間。比如我們new byte[233];這里233就是capacity。類比數組,capacity在指定后不允許改變。capacity()有參則是setter,無參則是getter,下面的limit和position屬性同理。mark則稍有不同。
limit
界限(limit,原諒我不能信達雅),初始化時等于capacity,我們申請了capacity那么大的空間,但是我們未必時時刻刻都有那么大的數據。java就是用limit來界定我們的數據界限在哪,比如limit=10,capacity=20,那么10到20之間就是空閑空間(但是我們也不能直接使用這片空間)。我們所有的讀寫操作都受limit限制,不能操作超過limit的那片空間。如果我們想用上面那片10到20之間的空間,那么我們就要使limit等30。然后我們就能操作30之前的空間。limit最大能等于capacity,因為我們就申請了capacity那么大的空間,如果limit超過capacity那就會操作了不屬于ByteBuffer,跟數組越界一個道理。記住一句話,我們所有的讀寫操作都起于position,終于limit,最大能等于capacity。
position
定位(position),初始化時等于0,指向我們下一個要操作的位置,有點類似PC指針。無論我們是要讀還是寫,操作的都是position指向的位置,操作完position就加一,指向你下一個要操作的位置。position最大能等于limit,此時就不能再操作了,因為你操作完position加一就大于limit了,那就越界了,會報java.nio.BufferOverflowException異常。
Mark
標記(Mark),初始化時等于-1,類似書簽,我們在某時刻調用mark()方法,那么mark將等于position。然后我們想回到我們mark的地方時可以調用reset()方法。網絡用語馬克就是mark音譯。
ByteBuffer方法
allocate()
public static ByteBuffer allocate(int capacity)
Allocates a new byte buffer.
The new buffer’s position will be zero, its limit will be its capacity, its mark will be undefined, and each of its elements will be initialized to zero. It will have a backing array, and its array offset will be zero.
ByteBuffer初始化方法,參數是int,也就capacity。比如ByteBuffer byteBuffer=ByteBuffer.allocate(20);就是為ByteBuffer開辟了一塊20字節大小的內存空間。注意指定capacity后就不能更改了,除非你重新new一個ByteBuffer,不過那就是另外一個ByteBuffer了。
order()
public final ByteBuffer order(ByteOrder bo)
Modifies this buffer’s byte order.
Parameters:
bo - The new byte order, either BIG_ENDIAN or LITTLE_ENDIAN
ByteBuffer是有字節序的,所謂字節序就是把字節放進ByteBuffer的順序。比如我們ByteBuffer的內存地址是0xFFFF 0000到0xFFFF 00FF,我們現在要把一個byte數組放進ByteBuffer,那么我們是從0xFFFF 00FF開始放起,還是從0xFFFF 0000開始放起呢?ByteOrder就是指明我們按照什么順序放的。byte還看不出什么不同,但是當我們讀寫那些不止一個字節的對象時就體現出不同了,比如讀int類型從0xFFFF 0000到0xFFFF 0004跟從0xFFFF 0004到0xFFFF 0000完全就是兩個不同的數。order()有參數就是設置字節序,沒參數就是返回ByteBuffer當前字節序。不過這個感覺一般來說不用管。
put()
public abstract ByteBuffer put(byte b)
Relative put method (optional operation).
Writes the given byte into this buffer at the current position, and then increments the position.
就是把數據放進ByteBuffer的方法,有多種變種,比如put(byte),put(byte[]),put(byte[] src,int offset,int length),put(ByteBuffer src)等等。你寫入多少個字節的數據position就加多少。
flip()
public final Buffer flip()
Flips this buffer. The limit is set to the current position and then the position is set to zero. If the mark is defined then it is discarded.
flip()方法就是把limit設置成當前position,然后position=0,附帶把mark置-1,也就是舍棄你可能有的標記。簡單來說這個方法的作用就是把寫模式變成讀模式。比如你初始化一個ByteBuffer,此時position=0,limit=capacity。然后你向其中寫入了5個字節的數據(假設capacity大于5),此時position=5,limit=capacity。現在你想把寫入的5字節數據讀出來,假如你直接讀,那么你會讀到位與5的數據,然后position=6。這顯然不符合我們的需求。我們需要把position置0,因為我們希望下個操作的數據位于0位置。這樣我們能正確讀出那五個數據了,但是我們沒有設置limit,那么我們完全有可能讀到5以后的數據。這樣也是不行的,那么我們就需要把limit設置成5,也就是寫完后position的位置。這樣我們就只會讀5個字節的數據,覺不會多讀。
array()
public final byte[] array()
Returns the byte array that backs this buffer (optional operation).
Modifications to this buffer’s content will cause the returned array’s content to be modified, and vice versa.
Invoke the hasArray method before invoking this method in order to ensure that this buffer has an accessible backing array.
前面說過ByteBuffer實質就是一個byte[],這個方法就是返回ByteBuffer底層的byte數組,也就是說你對ByteBuffer的所有操作實質就是操作這個byte數組,反之亦然。需要注意的是操作數組不會影響ByteBuffer的position,limit,mark等屬性,同時對數組的操作和一般數組沒有任何區別,不受ByteBuffer那些屬性影響。
get()
public abstract byte get()
Relative get method. Reads the byte at this buffer’s current position, and then increments the position.
用flip()或者手動準備好讀后,可以使用get()方法讀取ByteBuffer的數據,和put()方法一樣get()有很多延伸,可以根據自己需要選取。
wrap()
public static ByteBuffer wrap(byte[] array)
Wraps a byte array into a buffer.
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 array.length, its position will be zero, and its mark will be undefined. Its backing array will be the given array, and its array offset> will be zero.
文檔說的很清楚了,就是以你給定的字節數組為底層數組構建一個ByteBuffer。
//wrap()創建ByteBuffer byte[] array=new byte[233]; ByteBuffer byteBuffer=ByteBuffer.wrap(array);//allocate創建ByteBuffer ByteBuffer byteBuffer=ByteBuffer.allocate(233); byte[] array=byteBuffer.array();上面兩種創建ByteBuffer的方式,前者不會開辟新的內存空間,而是直接使用array的內存空間,同時保留array數組原有數據。而后者會開辟新的內存空間。
clear()
public final Buffer clear()
Clears this buffer. The position is set to zero, the limit is set to the capacity, and the mark is discarded.
clear()做的就是把position=0,limit=capacity,mark=-1,clear()只是移動指針,不改變ByteBuffer里面的數據。此時如果你要寫,那么ByteBuffer就相當于空的,如果你要讀,那么ByteBuffer就相當于寫滿數據的。
rewind()
public final Buffer rewind()
Rewinds this buffer. The position is set to zero and the mark is discarded.
如上,position=0,mark被舍棄,也就是說你讀寫到一半或讀寫完了,現在想從頭開始,那就調用rewind()方法,從頭開始。
campact()
public abstract ByteBuffer compact()
Compacts this buffer (optional operation).
The bytes between the buffer’s current position and its limit, if any, are copied to the beginning of the buffer. That is, the byte at index p = position() is copied to index zero, the byte at index p + 1 is copied to index one, and so forth until the byte at index limit() - 1 is copied to index n = limit() - 1 - p. The buffer’s position is then set to n+1 and its limit is set to its capacity. The mark, if defined, is discarded.
The buffer’s position is set to the number of bytes copied, rather than to zero, so that an invocation of this method can be followed immediately by an invocation of another relative put method.
如上所說,調用campact()方法會把position和limit之間的數據移動到ByteBuffer開始的地方,然后position=limit-position,也就是position接在被轉移的數據后面,然后limit=capacity。這個方法的作用是把我們未讀完的數據放到前面,以便我們接著后面寫入數據,因為我們不能期望一次把所有數據讀完。總會出現在還未讀完數據的時候需要寫入數據的情況,此時如果你不需要未讀的那些數據,可以clear(),如果需要保留那些數據則campact()。
最后
其實寫博客很難受,要考慮寫得對寫得全,又要通俗易懂,寫到最后我都有點偷工減料了,如果有哪里不清楚,自己寫段簡單代碼驗證一下就是了,更多ByteBuffer特性用法請參閱官方API文檔。同時如果有哪里寫錯了還請不吝賜教。最后祝各位能找到自己的真物。
總結
以上是生活随笔為你收集整理的ByteBuffer详解(大概2333)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程的修炼(中英双语)
- 下一篇: 11-用杂志拼接信件(蓝桥杯)