JAVA基础 - BYTEBUFFER是什么?

  1. Buffer 类是 java.nio 的构造基础。一个 Buffer 对象是固定数量的、数据的容器,其作用是一个存储器或者分段运输区。在这里,数据可被存储并在之后用于检索。缓冲区可以被写满或释放。对于每个非布尔类型的、原始数据类型都有一个缓冲区类,即 Buffer 的子类有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和 ShortBuffer,是没有 BooleanBuffer 之说的。尽管缓冲区作用于它们存储的原始数据类型,但缓冲区十分倾向于处理字节。
  2. Buffer及其子类都不是线程安全的,若多线程操作该缓冲区,则应通过同步来控制对该缓冲区的访问。
  3. 每个Buffer都有以下四个属性:
    (1) capacity:容量,缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,且永远不能被改变
    (2) limit:上界,缓冲区的第一个不能被读或写的元素。缓冲区创建时,limit 的值等于 capacity 的值。假设 capacity = 1024,我们在程序中设置了 limit = 512,说明Buffer 的容量为 1024,但是从 512 之后既不能读也不能写,因此可以理解成,Buffer 的实际可用大小为 512
    (3) position:位置,下一个要被读或写的元素的索引。位置会自动由相应的 get() 和 put() 函数更新。 这里需要注意的是positon的位置是从0开始,比如,已经写入buffer 3个元素那那么position就是指向第4个位置,即position设置为3(数组从0开始计)
    (4) mark:标记,一个备忘位置。保存某个时刻的position指针的值,通过调用mark()实现,当mark被置为负值时,表示废弃标记。标记在设定前是未定义的(undefined)。使用场景是,假设缓冲区中有 10 个元素,position 目前的位置为 2(也就是如果get的话是第三个元素),现在只想发送 6 - 10 之间的缓冲数据,此时我们可以 buffer.mark(buffer.position());即把当前的 position 记入 mark 中,然后 buffer.postion(6);此时发送给 channel 的数据就是 6 - 10 的数据。发送完后,我们可以调用 buffer.reset() 使得 position = mark,因此这里的 mark 只是用于临时记录一下位置用的
    (5) position和limit之间的距离指定了可读/写的字节数
    (6) mark,position,limit,capacity大小关系:
	-1 <= mark <= position <= limit <= capacity
			0<= position <= limit <= capacity
  1. 常用的方法一:
    (1) clear(),把position设为0,把limit设为capacity,取消标记,一般在把数据写入Buffer前调用,Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,调用clear()方法以后,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。源码如下:
    public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
    }

    (2) compact(),如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先写些数据,那么使用compact()方法。compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
    (3) flip(),把limit设为当前position,把position设为0,取消标记,一般在从Buffer中读取数据前调用。源码如下:
    public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
    }

    (4) rewind(),把position设为0,limit不变,一般在把数据重写入Buffer前调用。源码如下:
    public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
    }

    (5) hasRemaining(),当缓冲区至少还有一个元素时,返回true;
    (6) remaining(),position和limit之间字节个数;
    (7) reset(),将position的值还原成上次调用mark()方法后的position的值。源码如下:
    public final Buffer reset() {
    int m = mark;
    if (m < 0)
    throw new InvalidMarkException();
    position = m;
    return this;
    }

  2. 常用方法二:
    (1) allocate(),分配一个具有指定大小的底层数组,并将它包装到一个缓冲区对象中,用静态方法 allocate() 来分配缓冲区;
    (2) wrap(),将一个已有的byte数组包装出一个新的bytebuffer对象;
    (3) slice(),根据现有的缓冲区创建一个子缓冲区。也就是它创建一个新的缓冲区,新缓冲区与原来的缓冲区的一部分共享数据,子缓冲区和缓冲区 共享同一个底层数据数组,分片操作是根据当前position以及limit的值来确定的;
    (4) order(),返回ByteBuffer的字节序;

  3. 视图缓冲区,可以用ByteBuffer对象创建其他类型的缓冲区,新缓冲区共享原始ByteBuffer的全部或者部分内存,这样的缓冲区被叫做视图缓冲区,就是通过源缓冲区创建其他的基础数据类型的缓冲区,新缓冲区和源缓冲区共享数据,但各自维护自己的属性(capacity、limit、position、mark)。

  4. 使用Buffer读/写数据一般遵循以下四个步骤:
    (1) 写入数据到Buffer;
    (2) 调用flip()方法;
    (3) 从Buffer中读取数据;
    (4) 调用clear()方法或者compact()方法;

  5. 当向buffer写入数据时,buffer会记录下写了多少数据;一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式;在读模式下,可以读取之前写入到buffer的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。
    有两种方式能清空缓冲区:调用clear()或compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
    在这里插入图片描述在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cloneme01

谢谢您的支持与鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值