/*缓冲区(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 }