2.Buffer 緩沖區
/*緩沖區(Buffer)*/
Buffer 就像一個數組,可以保存多個相同類型的數據。根據數據類型不同(boolean 除外),有以下Buffer常用子類:
/*ByteBuffer*/(常用) 、CharBuffer 、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer
上述Buffer 類,他們都采用相似的方式進行管理數據,只是各自管理的數據類型不同而已。都是通過如下方法獲取一個Buffer對象:
static XxxBuffer allocate(int capacity): 創建一個容量為 capacity 的 XxxBuffer對象
/*緩存區的基本屬性*/
Buffer中的重要概念:
1.容量(capacity):表示Buffer 最大數據容量,緩沖區容量不能為負,並且創建後不能修改 (創建Buffer對象時 初始化)
2.限制(limit):第一個不應該讀取或寫入的數據的索引,(即位於limit後的數據不可讀寫)緩沖區的限制 不能為負,並且不能大於其容量
3.位置(position):下一個要讀取或寫入的數據的索引。緩沖區的位置不能為負,並且不能大於其限制值
4.標記(mark)與重置(reset):標記也是一個索引,通過Buffer中的 mark() 方法指定Buffer中一個特定的position,之後可以通過調用reset()方法恢復到這個 position
標記、位置、限制、容量遵循以下不變式:/*0 <= mark <= position <= limit <= capacity*/
Buffer的常用方法
Bufffer clear() 清空緩沖區(索引重置為初始狀態)並返回對緩沖區的引用(但是緩沖區的數據依然存在,但是出於 “被遺忘” 狀態)
Buffer flip() 將緩沖區的界限設置為當前位置,並將當前位置重置為0 (即準備開始操作緩沖區裏面的數據)
緩沖區的數據操作
Buffer 所有子類提供了 兩個用於數據操作的方法: get() 與 put() 方法
/*直接與非直接緩沖區*/
非直接緩沖區:通過allocate() 方法 分配緩沖區,將緩沖區建立在 JVM內存中
直接緩沖區: 通過 allocateDirect() 方法 分配直接緩沖區,將緩沖區建立在物理內存中,可以提高效率
字節緩沖區要麽是直接的,要麽是非直接的。如果是直接字節緩沖區,則Java 虛擬機 會盡最大努力直接在此緩沖區上執行本機 I/O 操作
即直接緩沖區: 通過過一個 ‘物理內存映射文件’ ,將本來要放在JVM內存中的緩沖區 直接放到 物理內存中
非直接緩沖區: 將緩沖區 先放到JVM 的內存中,然後通過 copy ,將內容復制到 內核地址空間(物理內存) ,寫入磁盤
直接緩沖區少了一個 copy 的過程,自然速度會更快,但是也有缺點:1.直接在物理內存上開辟和銷毀空間的代價很大,2.基本上失去了對緩沖區數據的控制,無法控制其銷毀
所以:僅在直接緩沖區能在程序性能方面帶來明顯好處時分配他們
1 /* 2 * 一、緩沖區(Buffer):在Java NIO中負責數據的存取。緩沖區就是數組。用於存儲不同數據類型的數據 3 * 4 * 根據數據類型不同 (boolean 除外),提供了相應類型的緩沖區 5 * ByteBuffer(常用) 、CharBuffer、ShortBuffer等 6 * 7 * 上述緩沖區 的 管理方式幾乎一致,通過 allocate() 獲取緩沖區 8 * 9 * 二、緩沖區存取數據的兩個核心方法: 10 * put():存入 數據到緩沖區 11 * get():獲取緩沖區的數據 12 * 13 * 三、緩沖區的四個核心屬性 14 * 1.capacity : 容量,表示Buffer 最大數據容量,緩沖區容量不能為負,並且創建後不能修改 (創建Buffer對象時 初始化) 15 * 16 * 2.限制(limit):第一個不應該讀取或寫入的數據的索引,(即位於limit後的數據不可讀寫) 17 緩沖區的限制 不能為負,並且不能大於其容量 18 3.位置(position):下一個要讀取或寫入的數據的索引。緩沖區的位置不能為負,並且不能大於其限制值 19 20 4.標記(mark)與重置(reset):標記也是一個索引,通過Buffer中的 mark() 方法指定Buffer中一個特定的position, 21 之後可以通過調用reset()方法恢復到這個 position 22 * 23 * 0 <= mark <= position <= limit <= capacity 24 * 25 * 四、直接緩沖區 和 非直接緩沖區 26 * 非直接緩沖區:通過allocate() 方法 分配緩沖區,將采取建立在 JVM內存中 27 * 直接緩沖區:通過 allocateDirect() 方法 分配直接緩沖區,將緩沖區建立在物理內存中,可以提高效率 28 * 29 * */ 30 31 public class TestBuffer { 32 33 @Test 34 public void test3() { 35 ByteBuffer buffer1 = ByteBuffer.allocateDirect(1024); 36 System.out.println(buffer1.isDirect()); 37 ByteBuffer buffer2 = ByteBuffer.allocate(1024); 38 System.out.println(buffer2.isDirect()); 39 } 40 41 @Test 42 public void test2() { 43 String str = "abcd"; 44 ByteBuffer buffer = ByteBuffer.allocate(1024); 45 46 buffer.put(str.getBytes()); 47 48 buffer.flip(); 49 50 byte[] bytes = new byte[buffer.limit()]; 51 buffer.get(bytes,0,2); 52 53 //position = 2 54 System.out.println(new String(bytes)); 55 System.out.println(buffer.position()); 56 57 //標記當前 position 58 buffer.mark(); 59 60 //position = 4 61 buffer.get(bytes,2,2); 62 System.out.println(new String(bytes)); 63 System.out.println(buffer.position()); 64 65 //將 position reset 到 標記的位置 position = 2 66 buffer.reset(); 67 System.out.println(buffer.position()); 68 } 69 70 @Test 71 public void test1() { 72 //1.分配一個指定大小的緩沖區 73 ByteBuffer buffer = ByteBuffer.allocate(1024); 74 System.out.println("-------------allocate()-------------"); 75 System.out.println(buffer.position()); 76 System.out.println(buffer.limit()); 77 System.out.println(buffer.capacity()); 78 79 //2.利用 put() 存入數據到緩沖區 80 String str = "abcedf"; 81 buffer.put(str.getBytes()); 82 System.out.println("-------------put()-------------"); 83 System.out.println(buffer.position()); //此時 位置 索引會變成6,即下一個要讀取或寫入的數據的索引 是 6 (byte[6]) 84 System.out.println(buffer.limit()); 85 System.out.println(buffer.capacity()); 86 87 //3.使用 get() 讀取數據之前,需要調用 flip() 方法,切換到 讀取數據模式 (將position置為0,limit置為原先position) 88 //不然按照現在的所以 是無法讀取到任何數據的 89 buffer.flip(); 90 System.out.println("-------------flip()-------------"); 91 System.out.println(buffer.position()); 92 System.out.println(buffer.limit()); 93 System.out.println(buffer.capacity()); 94 95 //4.利用 get() 讀取緩沖區中的數據 96 //讀取 需要創建一個容器去裝 97 byte[] bytes = new byte[buffer.limit()]; 98 //將讀取到的數據 放到 這個 byte數組中 99 buffer.get(bytes); 100 101 System.out.println("-------------get()-------------"); 102 System.out.println(buffer.position()); 103 System.out.println(buffer.limit()); 104 System.out.println(buffer.capacity()); 105 System.out.println(new String(bytes,0,bytes.length)); 106 107 //5.rewind() 可重復讀 將位置設成 0 ,取消設置的 remark,現在就可以重新讀取了 108 buffer.rewind(); 109 System.out.println("-------------rewind()-------------"); 110 System.out.println(buffer.position()); 111 System.out.println(buffer.limit()); 112 System.out.println(buffer.capacity()); 113 114 //6.clear() 清空緩存區,緩沖區中的數據依然存在,但是 處於 ‘被遺忘’狀態 115 buffer.clear(); 116 System.out.println("-------------clear()-------------"); 117 System.out.println(buffer.position()); 118 System.out.println(buffer.limit()); 119 System.out.println(buffer.capacity()); 120 121 System.out.println((char)buffer.get()); 122 } 123 }
2.Buffer 緩沖區