一、前言
上一篇文章中我们对NIO的三大组件做了简单的介绍,接下来的文章会对着三大组件进行进一步详细的学习,在学习完三大组件之后,我们再开启Netty的学习。
二、Buffer
1、属性
顾名思义Buffer是缓冲区,从源码中可以看出Buffer是一个接口有许多的实现类我们以最常用的ByteBuffer为例。ByteBuffer有以下几个属性。
其中最重要的就是 byte[] hb这个属性,这是一个字节数组,在内存中是一块连续的空间,如下图。
2、主要属性
int mark:标志位,在读取的过程中我们可以设置一个标志位,下次再想读的时候可以从被标记的位置开始读取。
int position:指针,指向当前读取的位置
int limit:是用来控制每次写Buffer时的最大长度
int capacity:容量
long address:地址,这里的地址指的是,直接物理内存的地址。因为buffer分为jvm的buffer还有direct buffer(直接内存)
byte[] hb:字节数组,也是ByteBuffer中用于存放数据的地方,在内存中的表现是一块连续的空间
3、主要方法
1、ByteBuffer allocateDirect(int capacity):申请一块直接物理内存
2、ByteBuffer allocate(int capacity) :申请一块堆内存(JVM内存)
3、Buffer flip() :翻转,就是将指针重置,重头开始。
4、final Buffer clear():清空,其实也只是针对指针的移动,并不会删除原本数组中的内容。
5、abstract byte get() 和 abstract byte get(int index),这两个方法都是从数组中获取数据,不同的是 get()方法获取之后会将指针往后移动一位,而get(int index)则不会。
6、ByteBuffer put(byte b);往字节数组里写入数据。
三、代码演示
1、申请内存:ByteBuffer byteBuffer = ByteBuffer.allocate(10);
2、往ByteBuffer写入一个数据:byteBuffer.put(“h”.getBytes()); put方法本身很简单就是将数据写入数组中,并且移动指针。
3、获取字节数组的数据 get(int index)
System.out.println((char)byteBuffer.get(0)) :注意这里需要通过下标来获取,如果不写下标则会先移动指针(position)再获取
4、获取下一个字节Get方法:和上面不同的是先移动指针到下一个位置,然后在读取,这里不做演示
5、flip,假设现在数组是满的
flip之前:
flip:之后:其实就是移动了一下 position然后修改了一下 limit
5、clear:和flip相似唯一不同limit被设置为整个数组的长度(filp如果在数组不满的情况下,对于limit的设置和clear是不一样的)
完整代码
//申请一块长度为10个字节堆内存
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
//往ByteBuffer写入一个数据
byteBuffer.put("h".getBytes(StandardCharsets.UTF_8));
//读取第一个字节
System.out.println((char)byteBuffer.get(0));
//写入hello 剩下的字母
byteBuffer.put("ello".getBytes(StandardCharsets.UTF_8));
//翻转数组
byteBuffer.flip();
System.out.println("读取数据");
for(int i=0;i<5;i++){
System.out.print((char)byteBuffer.get()+" ");
}
//“清空”数组(其实不会清空,只是移动指针)
byteBuffer.clear();
//这里证明一下 数组中的内容并没有被清空只是指针被移动到了开头
System.out.println("clear之后读取数据");
for(int i=0;i<5;i++){
System.out.print((char)byteBuffer.get()+" ");
}
四、结束语
今天我们学习了ByteBuffer,对ByteBuffer中一些主要方法和属性做了解释,这些是为了之后Netty学习做铺垫,希望对你有所帮助。