一、Buffer是啥?
- 一個用於特定基本數據類型的容器。由 java.nio 包定義的,所有緩衝區都是 Buffer 抽象類的子類
- Java NIO 中的 Buffer 主要用於與 NIO 通道進行交互,數據是從通道讀入緩衝區,從緩衝區寫入通道中的。
二、 Buffer的子類
千言萬語勝不過一圖
從圖知除boolean 外,基本數據類型都有緩衝區
三、緩衝區的基本屬性
Buffer 中的重要概念:
- 容量 (capacity) :表示 Buffer 最大數據容量,緩衝區容量不能爲負,並且創建後不能更改。
- 限制 (limit):第一個不應該讀取或寫入的數據的索引,即位於 limit 後的數據不可讀寫。緩衝區的限制不能爲負,並且不能大於其容量。
- 位置 (position):下一個要讀取或寫入的數據的索引。緩衝區的位置不能爲負,並且不能大於其限制
- 標記 (mark)與重置 (reset):標記是一個索引,通過 Buffer 中的 mark() 方法指定 Buffer 中一個特定的 position,之後可以通過調用 reset() 方法恢復到這個 position.
- 標記、位置、限制、容量遵守以下不變式: 0 <= mark <= position <= limit <= capacity
是不是有點懵逼咧,沒事,看圖就知道了
常用方法:
- capacity()----返回的是緩衝區容量的大小。
- position()----返回position的值大小。
- limit()----返回此緩衝區的限制值limit.
- mark()----標記緩衝區中位置。
- reset()----將緩衝區位置position設置爲標記的位置。
- clear()----清空緩衝區,調用此方法將position設置爲0,limit的值設置爲緩衝區容量值,標記將被丟棄。
- flip()----調用此方法將limit設置當前position的值,position設置爲0,有標記情況下,標記將被丟棄。
- rewind()----調用此方法將position值設置爲0,標記將被丟棄.,limit值不會變化。
- remaining()----返回當前位置與限制limit之間的值,即limit-position的值。
- hasRemaing()—布爾類型,當前位置與限制值之間是否有元素。
- isDirect()----判斷此緩衝區是否爲直接緩衝區(調用allocateDirect()分配的是直接緩衝區,即不受JVM管控的堆外內存)。
其它一些方法請自行查看API
四、ByteBuffer緩衝區(以它爲例子)
- 創建緩衝區
直接看代碼
ByteBuffer buf1 = ByteBuffer.allocate(1024); //調用allocate()方法,創建直接緩衝區
ByteBuffer buf2 = ByteBuffer.allocateDirect(1024); //調用allocateDirect()方法,創建非直接緩衝區
- 如何讀取緩衝區的數據
直接看圖
五、直接緩衝區和非直接緩衝區???
說了老半天,它們兩者如何理解呀呀呀!!!,別急,往下看!!!
理解乾貨來了:
- 直接緩衝區的創建是由操作系統方面的代碼分配的,是JVM堆外的內存,直接分別緩衝區脫離了JVM的束縛,是IO操作方面的最佳選擇,但創建和銷燬直接緩衝區花銷更大
- 如果爲直接字節緩衝區,則 Java 虛擬機會盡最大努力直接在此緩衝區上執行本機 I/O 操作。也就是說,在每次調用基礎操作系統的一個本機 I/O 操作之前(或之後),虛擬機都會盡量避免將緩衝區的內容複製到中間緩衝區中(或從中間緩衝區中複製內容)。
- 非直接緩衝區分配的是JVM堆內存。
- 創建非直接緩衝區向通道傳輸數據底層可能會先創建一個臨時直接緩衝區,然後將非直接緩衝區數據放到臨時直接緩衝區,使用臨時緩衝區與IO進行交互,這會創建大量對象,但垃圾對象能得到及時回收
又瞎逼逼說了那麼多,還是不懂咋搞,沒事,看圖哈
六、奉上代碼(光說不練,歪把子)
package nio_study;
import java.nio.ByteBuffer;
/*
* 一、緩衝區(Buffer):在 Java NIO 中負責數據的存取。緩衝區就是數組。用於存儲不同數據類型的數據
*
* 根據數據類型不同(boolean 除外),提供了相應類型的緩衝區:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述緩衝區的管理方式幾乎一致,通過 allocate() 獲取緩衝區
*
* 二、緩衝區存取數據的兩個核心方法:
* put() : 存入數據到緩衝區中
* get() : 獲取緩衝區中的數據
*
* 三、緩衝區中的四個核心屬性:
* capacity : 容量,表示緩衝區中最大存儲數據的容量。一旦聲明不能改變。
* limit : 界限,表示緩衝區中可以操作數據的大小。(limit 後數據不能進行讀寫)
* position : 位置,表示緩衝區中正在操作數據的位置。
*
* mark : 標記,表示記錄當前 position 的位置。可以通過 reset() 恢復到 mark 的位置
*
* 0 <= mark <= position <= limit <= capacity
*
* 四、直接緩衝區與非直接緩衝區:
* 非直接緩衝區:通過 allocate() 方法分配緩衝區,將緩衝區建立在 JVM 的內存中
* 直接緩衝區:通過 allocateDirect() 方法分配直接緩衝區,將緩衝區建立在物理內存中。可以提高效率
*/
public class TestBuffer {
public void test1(){
String str = "abcde";
//1. 分配一個指定大小的緩衝區
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("-----------------allocate()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//2. 利用 put() 存入數據到緩衝區中
buf.put(str.getBytes());
System.out.println("-----------------put()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//3. 切換讀取數據模式
buf.flip();
System.out.println("-----------------flip()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//4. 利用 get() 讀取緩衝區中的數據
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
System.out.println("-----------------get()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//5. rewind() : 可重複讀
buf.rewind();
System.out.println("-----------------rewind()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
//6. clear() : 清空緩衝區. 但是緩衝區中的數據依然存在,但是處於“被遺忘”狀態
buf.clear();
System.out.println("-----------------clear()----------------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());
System.out.println((char)buf.get());
}
public void test2(){
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(str.getBytes());
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst, 0, 2);
System.out.println(new String(dst, 0, 2));
System.out.println(buf.position());
//mark() : 標記
buf.mark();
buf.get(dst, 2, 2);
System.out.println(new String(dst, 2, 2));
System.out.println(buf.position());
//reset() : 恢復到 mark 的位置
buf.reset();
System.out.println(buf.position());
//判斷緩衝區中是否還有剩餘數據
if(buf.hasRemaining()){
//獲取緩衝區中可以操作的數量
System.out.println(buf.remaining());
}
}
public void test3(){
//分配直接緩衝區
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
System.out.println(buf.isDirect());
}
}
七、分享結束
最後有興趣一起交流的,可以關注我的公衆號:這裏你能夠學到很實用的技巧,不是常用的我不說,公衆號回覆提取碼即可獲取以下學習資料啦啦啦啦,喜歡就拿去吧!!
-
Java web從入門到精通電子書
-
Python機器學習電子書
-
Python400集(北京尚學堂)
-
JavaScript項目案例、經典面試題
-
Java300集(入門、精通)
-
Java後端培訓機構錄集(同事培訓內部提供)
參考資料:
圖片來自:b站尚硅谷Java視頻_NIO 視頻教程
代碼來自:b站尚硅谷Java視頻_NIO 視頻教程
侵立刪