NIO--buffer

0 继承关系

DirectBuffer
注意 只有DirectByteBuffer继承了 MappedByteBuffer,可以内存映射
在这里插入图片描述
HeapBuffer
在这里插入图片描述

1Buffer

1 缓冲区的抽象基类,其内部实现为一个数组或一个直接缓冲区。

2 该缓冲区读写两用,靠着游标position和上界limit标记【活跃区域】。
3 不管处于读模式还是处于写模式,【活跃区域】总是:[position, limit)。
4要特别区分【读模式】和【写模式】下各方法及参数的含义。

5缓冲区有四个关键属性(标记),它们的关系是: mark <= position <= limit <= capacity
6注意,这些属性表示的是相对于当前缓存区的位置(相对位置),而不是相对于内部存储结构的位置(绝对位置)。

  • 比如postion=1,代表的是当前缓冲区中索引为1的元素,而不是内部存储结构中索引为1的元素。
  • 当前缓冲区脱胎于其内部存储结构,该内部存储结构是共享的,可被多个缓冲区共享。
  • 区分每个缓冲区的【绝对起点】靠的是address字段和offset字段。

7 非直接缓冲区:(堆内存)

  • 通过allocate()分配缓冲区,将缓冲区建立在JVM的内存中。通过常规手段存取元素。
    

8 直接缓冲区:(堆外内存,可通过-XX:MaxDirectMemorySize设置大小)

  • 通过allocateDirect()分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率。通过Unsafe存取元素。
    

2 ByteBuffer转化

B,代表大端
L,代表小端
RB,代表只读大端
RL代表只读小端
在这里插入图片描述

3 DirectBuffer

R,代表只读
S 可读写、直接缓冲区,采用与平台字节顺序不同的字节序,其他部分与DirectCharBufferU相同
U,可读写、直接缓冲区,采用与平台字节顺序相同的字节序,其他部分与DirectCharBufferS相同
RS 只读,与平台字节顺序不同的字节序
RU 只读,与平台字节顺序相同的字节序

在这里插入图片描述

4 buffer api

4.1使用 Buffer 读写数据一般遵循以下四个步骤:

1)写入数据到 Buffer,一般有可以从 Channel 读取到到缓冲区中,也可以调用 put 方法写入。

2)调用 flip() 方法,切换数据模式。

3)从 Buffer 中读取数据,一般从缓冲区读取数据写入到通道中,也可以调用 get 方法读取。

4)调用 clear() 方法或者 compact() 方法清空缓冲区。

当向 buffer 写入数据时,buffer 会记录下写了多少数据。一旦要读取数据,需要通过 flip() 方法将 Buffer 从写模式切换到读模式。

在读模式下,可以读取之前写入到 buffer 的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。

有两种方式能清空缓冲区:

1)clear() 方法会清空整个缓冲区。

2)compact() 方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

4.2 capacity、position和limit

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成 Buffer 对象,

并提供了一组方法,用来方便的访问该块内存。为了理解 Buffer 的工作原理,需要熟悉它的三个属性:

capacity
position
limit
position 和 limit 的含义取决于 Buffer 处在读模式还是写模式。不管 Buffer 处在什么模式,capacity 的含义总是一样的。

这里有一个关于 capacity,position 和 limit 在读写模式中的说明:

4.2.1 capacity

作为一个内存块,Buffer 有一个固定的大小值,也叫"capacity"。你只能往里写 capacity 个 byte、long,char 等类型。

一旦 Buffer 满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

4.2.2 position

当你写数据到 Buffer 中时,position表示当前的位置,指向下一个写位置。初始 position 值为0。

当一个 byte、long 等数据写到 Buffer 后,position会向前移动到下一个可插入数据的 Buffer 单元。

position 最大可为 capacity –1 当读取数据时,也是从某个特定位置读。

当将 Buffer 从写模式切换到读模式,position 会被重置为 0。当从 Buffer 的 position 处读取数据时,

position 向前移动到下一个可读的位置。

4.2.3 limit

在写模式下,Buffer 的 limit 表示你最多能往 Buffer 里写多少数据。写模式下,limit 等于 Buffer 的 capacity。

当切换Buffer到读模式时,limit 表示你最多能读到多少数据。因此,当切换Buffer到读模式时,

limit 会被设置成写模式下的 position 值。

换句话说,你能读到之前写入的所有数据,即 limit 被设置成已写数据的数量,这个值在写模式下就是 position,

因为position从0开始,就像上图的写入ABCD四个值,position指向第5个元素位置,即position是4,

切换到读模式下,将position赋值给limit,即limit是4,表示最多能读取多少个元素。

4.3 Buffer 的分配

要想获得一个Buffer对象首先要进行分配。每一个Buffer类都有一个allocate方法。

分配48字节capacity的ByteBuffer的例子:

ByteBuffer buf = ByteBuffer.allocate(48);

分配一个可存储1024个字符的CharBuffer:

CharBuffer buf = CharBuffer.allocate(1024);

4.4、向Buffer中写入数据

写数据到Buffer有两种方式:

1)从Channel写到Buffer。

2)通过Buffer的put()方法写到Buffer里。

从Channel写到Buffer的例子:

int bytesRead = inChannel.read(buf); // 从Channel(通道)读取到Buffer(缓冲区)中

通过put方法写Buffer的例子:

buf.put(127);

put方法有很多版本,允许你以不同的方式把数据写入到Buffer中。

例如,写到一个指定的位置,或者把一个字节数组写入到Buffer。

4.5、flip()方法使用

在这里插入图片描述

flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

换句话说,position 现在用于标记读的位置,limit 表示之前写进了多少个 byte、char 等现在能读取多少个 byte、char 等。

4.6、从Buffer中读取数据

从Buffer中读取数据有两种方式:

1)从Buffer读取数据到Channel。

2)使用get()方法从Buffer中读取数据。

从Buffer读取数据到Channel的例子:

// 从Buffer中读取数据写入到通道中

int bytesWritten = inChannel.write(buf);

使用get()方法从Buffer中读取数据的例子:

byte aByte = buf.get();

get方法有很多版本,允许你以不同的方式从Buffer中读取数据。

例如,从指定position读取,或者从Buffer中读取数据到字节数组。

4.7、rewind()方法

Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。

limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

4.8、clear()和compact()方法

一旦读完Buffer中的数据,需要让Buffer准备好再次被写入可以通过clear()或compact()方法来完成。

如果调用的是clear()方法,position将被设回0,limit被设置成capacity的值。换句话说,Buffer被清空了。

Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,

调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。

如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先写些数据,那么使用compact()方法。

compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。

limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

4.9、mark()和reset()方法

通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。

之后可以通过调用Buffer.reset()方法恢复到这个position。例如:

buffer.mark();

//调用buffer读写方法,下面通过调用reset恢复到调用前的position位置。

buffer.reset(); // set position back to mark

4.10、equals()和compareTo()方法

可以使用equals()和compareTo()方法两个Buffer。

equals()

当满足下列条件时,表示两个Buffer相等。

1)有相同的类型(byte、char、int等)。

2)Buffer中剩余的byte、char等的个数相等。

3)Buffer中所有剩余的byte、char等都相同。

如你所见,equals只是比较Buffer的一部分,不是每一个在它里面的元素都比较。

实际上,它只比较Buffer中的剩余元素。

compareTo()

compareTo()方法比较两个Buffer的剩余元素(byte、char等),如果满足下列条件,则认为一个Buffer"小于"另一个Buffer。

1)第一个不相等的元素小于另一个Buffer中对应的元素。

2)所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值