- 谈及Java NIO,最核心的三个组件就是
Channel
通道ByteBuffer
读写缓冲区Selector
多路复用器
- 核心之一就是在对
ByteBuffer
的读写操作上。
ByteBuffer
为NIO中的字节缓冲区,相对于BIO
的Stream
流只支持写入或者读取单向操作,ByteBuffer
是双向的,支持读和写。
- 类型
DirectByteBuffer
- 使用的是操作系统级别的内存,分配比较慢,但是数据的读写比较快,因为少了一次从系统内存到JVM内存的复制过程
- 初始化方法:
ByteBuffer.allocateDirect(1024 * 4);
HeapByteBuffer
- 使用的是JVM的堆内存,对于JVM来说,分配比较快,但是读写比较慢,因为需要将操作系统内存里的数据复制到JVM内存
- 初始化方法:
ByteBuffer.allocate(1024 * 4);
- 核心属性
capacity
ByteBuffer
的容量,这个值在ByteBuffer
初始化的时候就确定下来了。不论是在读还是在写模式下,这个值都不变。
position
- 写模式下:
- 该值表示当前写到了
ByteBuffer
的哪个位置,ByteBuffer
初始化时,这个值为0。 position
的最大值为capacity-1
。
- 读模式下:
- 当从写模式切换到读模式,会将
position
重置为0,即从ByteBuffer
的起始位置开始读取数据。
limit
- 写模式下:
limit
为最大可写入的数据量,即ByteBuffer
的最大容量,值为capacity
- 读模式下:
- 当从写模式切换从读模式,
limit
将会被设置为读模式下的position
值,即可读取的最大数据量。
- 核心方法
flip()
- 将写模式切换为读模式
- 会触发的对核心属性的操作:
- 将
position
设置为0
,即从ByteBuffer
起始位置开始读。 - 将
limit
设置为写模式下position
的值,即最大可读取的数据量大小。
mark()
- 标记当前
position
位置
reset()
- 将
position
指向上一次mark()
所指向的位置,可以从这个位置重复向下读取数据
clear()
- 在逻辑上清空ByteBuffer里的数据,实际上不清空数据
- 会触发的动作:
- 将
limit
设置为capacity
position
指向起始位置0
- 提示:实际上数据并未清理,只是下次是从0的位置开始写入数据,效果上像是数据清空了。
- 提示:如果
ByteBuffer
中的数据并未完全读完,调用这个方法将忽略那些未读取的数据。
compact()
- 如果并未读取完
ByteBuffer
中的数据,调用compact()
会将position~limit
之间的数据拷贝到ByteBuffer
的起始处,并且position
为剩余数据量的大小,下次再往ByteBuffer
中写入数据时,将在position
位置继续往下写,不会覆盖历史数据。
hasRemaining()
- 判断缓冲区中是否还有未读数据
- 将数据写入ByteBuffer的方式
byteBuffer.put(x)
channel.read(byteBuffer)
- 从ByteBuffer中读取数据的方式
byteBuffer.get()
channel.write(bytebuffer)
# 代码演示
/** * ByteBuffer的代码演示 * * @author futao * @date 2020/7/7 */ public class ByteBufferDemo { public static void main(String[] args) { // ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 * 4); ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 4); // Q: 初始化之后,这三个值分别是多少呢? System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); //向ByteBuffer写入数据 byteBuffer.put("hello, 喜欢天文的pony站长~".getBytes(Constants.CHARSET)); // Q: 向ByteBuffer中写入数据之后,哪些值会发生变化呢? System.out.println(StringUtils.repeat("=", 10) + "写入数据之后" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); //将ByteBuffer从写模式调整为读模式 byteBuffer.flip(); //将ByteBuffer从写模式调整为读模式之后,ByteBuffer的哪些值会发生变化? System.out.println(StringUtils.repeat("=", 10) + "调整ByteBuffer为读模式之后" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); //从ByteBuffer中读取一个字节 byteBuffer.get(); // Q: 从ByteBuffer中读取一个字节之后,哪些值会发生变化? System.out.println(StringUtils.repeat("=", 10) + "从ByteBuffer中读取一个字节之后" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); // 记录一个标记 byteBuffer.mark(); // 继续往下读取 byteBuffer.get(); System.out.println(StringUtils.repeat("=", 10) + "记录一个标记之后继续往下读取" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); //重置position到上一次mark()的标记位置 byteBuffer.reset(); System.out.println(StringUtils.repeat("=", 10) + "reset之后" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); System.out.println("byteBuffer中是否还有数据:" + byteBuffer.hasRemaining()); //拷贝未读取的数据到缓冲区最前面 byteBuffer.compact(); System.out.println(StringUtils.repeat("=", 10) + "compact之后" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); //逻辑上清空数据=>实际上只是指针的变化 byteBuffer.clear(); System.out.println(StringUtils.repeat("=", 10) + "clear之后" + StringUtils.repeat("=", 10)); System.out.println("position: " + byteBuffer.position()); System.out.println("capacity: " + byteBuffer.capacity()); System.out.println("limit: " + byteBuffer.limit()); } }
- 先不要看结果,自己思考一下哟,逻辑还是很清晰的~
是不是与你思考的一致~
# 源代码
- 源代码都给你了你还不看看?