2023-09-23
原文作者:李林超 原文地址: https://www.lilinchao.com/archives/2088.html

[TOC]

一、bytebuffer内部结构

1.1 属性介绍

Bytebuffer有以下重要属性:

  • capacity(容量) :缓冲区的容量。通过构造函数赋予,一旦设置,无法更改。
  • position(指针) :读写指针,记录数据读写的位置,缓冲区的位置不能为负,并且 不能大于limit
  • limit(读写限制) :缓冲区的界限。位于limit 后的数据不可读写。缓冲区的限制不能为负,并且 不能大于其容量

1.2 结构

  • 写模式

当缓冲区刚创建成功时

202309232223222051.png

写模式下,position 是写入位置,limit 等于容量。

下图表示写入了 4 个字节后的状态:

202309232223228932.png

Position移动到第5个字节开始位置

  • 读模式

flip动作发生后,position切换为读取位置,limit切换为读取限制

202309232223235933.png

  • position重新赋值到开始位置,因为读取数据从开始位置开始读取
  • limit被赋值为position写入时的最后位置,作为数据读取的最终位置

读取4个字节后,状态如下图:

202309232223242374.png

  • 当position位置与limit位置相同时,数据读取结束。
  • 数据未读取完重新切换到写模式时

compact 方法,是把未读完的部分向前压缩,然后切换至写模式

202309232223248545.png

二、ByteBuffer常见方法

  • put()

**描述:**可以将一个数据放入到缓冲区中。

进行该操作后,postition的值会+1,指向下一个可以放入的位置。capacity = limit ,为缓冲区容量的值。

202309232223255936.png

  • flip()

描述 :用来 切换对缓冲区的操作模式 ,由写->读 / 读->写

进行该操作后:

  • 如果是写模式->读模式,position = 0 , limit 指向最后一个元素的下一个位置,capacity不变;
  • 如果是读模式->写模式,则恢复为put()方法中的值。

202309232223261647.png

  • get()

描述 :该方法会读取缓冲区中的一个值

进行该操作后,position会+1,如果超过了limit则会抛出异常

202309232223269168.png

注意:get(i)方法不会改变position的值

  • rewind()

描述 :该方法 只能在读模式下使用

rewind()方法后,会恢复position、limit和capacity的值,变为进行get()前的值

202309232223275079.png

  • clean()

描述:会将缓冲区中的各个属性恢复为最初的状态,position = 0, capacity = limit

此时缓冲区的数据依然存在 ,处于“被遗忘”状态,下次进行写操作时会覆盖这些数据

2023092322232808110.png

  • mark()/reset()

描述 :mark 是在读取时,做一个标记,即使 position 改变,只要调用 reset 就能回到 mark 的位置

mark() :将postion的值保存到mark属性中

reset() :将position的值改为mark中保存的值

注意:rewind 和 flip 都会清除 mark 位置

  • compact()

描述 :compact会把未读完的数据向前压缩,然后切换到写模式

数据前移后,原位置的值并未清零,写时会 覆盖 之前的值

2023092322232865811.png

注意:此方法为ByteBuffer的方法,而不是Buffer的方法

clear()和compact()方法对比:

clear只是对position、limit、mark进行重置,而compact在对position进行设置,以及limit、mark进行重置的同时,还涉及到数据在内存中拷贝(会调用arraycopy)。**所以compact比clear更耗性能。**但compact能保存你未读取的数据,将新数据追加到为读取的数据之后;而clear则不行,若你调用了clear,则未读取的数据就无法再读取到了

需要根据情况来判断使用哪种方法进行模式切换

附参考文章:

《黑马程序员Netty教程》

阅读全文