JAVA基础---NIO---Buffer

概念:

在NIO中所有的数据都是用缓冲区处理的,任何时候访问NIO中的数据都是通过缓冲区操作。它本质上是一个数组,比如我们最常使用的Byte Buffer其实就是一个Byte数组。它还可以使除了boolean外很多其它数组类型,但是它不完全仅仅是一个数组,缓冲区还对数据提供了结构化访问以及维护读写位置等信息。

关键属性:

// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;

 /**
  * Returns the number of elements between the current position and the
  * limit.
  *
  * @return  The number of elements remaining in this buffer
  */
 public final int remaining() {
     return limit - position;
 }
  • Capacity:
    能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。当buffer写满时,需要先清空才能继续写入。

  • Limit:
    是buffer中不可以被读或者写的第一个元素的位置,limit的大小永远不会超过capacity(在写模式下,limit等于capacity)

  • Position:
    写模式下,position从0开始,每写入一个单位的数据,position前进一位,position最大可到达(capacity-1)的位置。当Buffer从写模式切换为读模式时,position将重置为0。读取数据时,同样地,position每读取一个单位,前进一位,此时,position最大可到达limit的位置(实际最大可读取的位置是(limit-1))。

  • 标记(Mark):
    一个备忘位置。调用mark( )来设定mark = postion。调用reset( )设定position = mark。标记在设定前是未定义的(undefined)。

  • remaining:
    这个缓冲区中剩余元素的数量

基础API用法:

先创建一个容量为16的intBuffer看一下

 IntBuffer intBuffer = IntBuffer.allocate(16);
 
 IntStream.rangeClosed(1,10).forEach(intBuffer::put);
 
  while (intBuffer.hasRemaining()){
            System.out.println(intBuffer.get());
        }

在这里插入图片描述
进入到源代码我们可以看到底层实现确实是数组,debug中也可以清晰的看到此时创建了16个数组
在这里插入图片描述

put():

下面我们往里面填充几个数值看看参数都有什么变化:
在这里插入图片描述
在注入10个数值后,数组对应坐标都有了值,同时position指针也移动到了目前数组10的位置

flip():

翻转方法是最常使用的一个方法,我们可以看到调用此方法后position重置到了0回到了数组的初始位置,而limit指向了之前position位置。
在这里插入图片描述
源码中给了详细的解释,逻辑也十分简单,主要是对position指针复原到数组头,limit指向数组当前实际存储的最后位置,方便进行后续的写操作等

/**
     * Flips this buffer.  The limit is set to the current position and then
     * the position is set to zero.  If the mark is defined then it is
     * discarded.
     *
     * <p> After a sequence of channel-read or <i>put</i> operations, invoke
     * this method to prepare for a sequence of channel-write or relative
     * <i>get</i> operations.  For example:
     *
     * <blockquote><pre>
     * buf.put(magic);    // Prepend header
     * in.read(buf);      // Read data into rest of buffer
     * buf.flip();        // Flip buffer
     * out.write(buf);    // Write header + data to channel</pre></blockquote>
     *
     * <p> This method is often used in conjunction with the {@link
     * java.nio.ByteBuffer#compact compact} method when transferring data from
     * one place to another.  </p>
     *
     * @return  This buffer
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

hasRemaining():

判断当前缓存中是否还有值,每读取一个值position就会往后移动一位,知道最后position=limit取出所有值退出循环

 public final boolean hasRemaining() {
        return position < limit;
    }

在这里插入图片描述

compact

这个方法起初看了很多解释都不太理解云里雾里的感觉,自己打一遍断点就清晰很多。它的作用就是将当前position前的已读数据清除,再将position到limit之间的未读数据复制到数组头部(注意遗留下来的数据仍然存在,之后加入新值时会被覆盖掉)。position重置到limit减去当前position的位置。即移动之后未读值的位置,当有新值加入时将从此位置进行插入。看例子就明白了语言有点不太直观

public IntBuffer compact() {
        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
        position(remaining());
        limit(capacity());
        discardMark();
        return this;
    }

根据这段代码打断点来看一下,我手动将position设置为3模拟当前读取到了3这种场景

   IntBuffer intBuffer = IntBuffer.allocate(16);

        IntStream.rangeClosed(1,10).forEach(intBuffer::put);

        intBuffer.flip();

        intBuffer.position(3);

        intBuffer.compact();

        intBuffer.put(11);

        intBuffer.put(12);

在这里插入图片描述
执行compact方法后position指针指向了7的位置,之前的旧值仍然存在。我们继续添加新值就会将此覆盖掉,从而达到资源的最大利用。到这里应该就恍然大悟了吧。clear()方法只是把指针移到位置0,并没有真正清空数据。而compact会清楚position之前的已读数据。
在这里插入图片描述

slice():

缓冲区切片,将一个大缓冲区的一部分切出来,作为一个单独的缓冲区,但是它们公用同一个内部数组。切片从原缓冲区的position位置开始,至limit为止。原缓冲区和切片各自拥有自己的属性。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值