NIO 源码基础篇 - buffer

一 NIO 是非阻塞,主要是Channel , Selector, Buffer ,我们来学习下Buffer,此图不全。

 

发现buffer,java 实现了除了boolean 类型的其他的7中基础数据类型。

Buffer 是指一个存放基元类型的数据容器。

如何定义一个Buffer。

     从构造函数的参数可以看出,需要传递4个参数。

    mark:标记的位置,重新标记读写的position位置。

    pos: 缓存下一个将要读取或或写的位置。

    lim:  限制写入或读取的长度大小

    cap: 表示初始化后buffer对象的长度。

 Buffer(int mark, int pos, int lim, int cap) {       // package-private
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("
                                                   + mark + " > " + pos + ")");
            this.mark = mark;
        }
    }

  在构造函数中对lim / pos 进行了预判。

 public final Buffer limit(int newLimit) {
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        limit = newLimit;
        if (position > limit) position = limit;
        if (mark > limit) mark = -1;
        return this;
    }

     首先 limit 限制必须满足小于capacity的限制,而且不能为负数,不然会抛出异常。

     如果当前的position大于limit的限制,则把position值进行负值给limit。

     前文说了mark是标记position的位置的,如果mark大于limit的话,怎丢弃标志mark,-1 表示丢弃。

 public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }

  对position位置的检测,position 不能大于limit ,而且不能为负数,否则抛出异常。

  同时mark如果大于position了,则被丢弃。这里你是否有疑问,mark的值是有position复值,怎么会和position不一致呢。查看    源码,代码里确实如此,不过初始化的时候,需要做mark校验检查的。

 public final Buffer mark() {
        mark = position;
        return this;
    }

  -1 表示丢弃?

 final void discardMark() {                          // package-private
        mark = -1;
    }

 buffer的作用是用来进行读写数据,数据不是write 就 read.

   /** <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>
     */

  public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

   /** <blockquote><pre>
     * out.write(buf);    // Write remaining data
     * buf.rewind();      // Rewind buffer
     * buf.get(array);    // Copy data into array</pre></blockquote>
     *
     * @return  This buffer
     */

 public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

 这个两个方法都可以用与buffer的读取状态切换,哪有什么区别的,flip() 比 rewind 多了一行代码。

rewind 每次操作都是buffer的全部数据假设limit=cap。 而flip是有限制的。

还有一写辅助操作buffer 的辅助方法。

  剩余未操作的数据大小

public final int remaining() {
        return limit - position;
    }

判断是否可操作

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

清除并不是真正的清除数据,是改变position值和限制大小,如何避免多读取数据呢,关键在于limit 的值=position,如果数据操作了。就做限制,读取数据就不会出错。

  public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }
 public final Buffer reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }

重设只是改变position的值设置为mark,在mark位置进行重新的操作。

以上的操作并没有真正清除数据,只是进行数据的覆盖。

边界检查

static void checkBounds(int off, int len, int size) { // package-private
        if ((off | len | (off + len) | (size - (off + len))) < 0)
            throw new IndexOutOfBoundsException();
    }

off: 开始索引

len:操作的数组长度

size: 数组的大小

'||' 表示只要一个满足都满足,不再进行其他检查判断。

‘|’ 表示按位或, 负数|任何数都是负数。

总结:

             Buffer 是 NIO出现的类,在做数据的序列化 传输上使用。

             Buffer 使用前必须指定大小,这个空间后期不会改变,是设计的一方面的缺陷吧。

           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值