Java NIO深入(Buffer)-我们到底能走多远系列(18)

我们到底能走多远系列(18)

扯淡:最近想要跳槽,现公司的主管不高兴,没提的时候关系好像很好,提的时候我比较坚决,他硬要我留一个月,老实说我想弄个三周就好了,对,国际惯例一个月,我也是想砍个一周下来休息下,他居然恐吓我,表达出我不仁他就不义的态度,表示可以再没走的时候为难我。现在开始挑我工作毛病了,态度已经不行了,有点装不住了,哈哈。我想,你这么搞我,我交接也不会尽全力了的,做到本职就滚蛋,留下的坑,你们慢慢填。

  最近一个月,经历了些事情,又教育了我一边,要投资自己,让自己变强,才能在有风雨时不倒。侥幸想在别人的树下躲避风雨的,今天可能过了关,包不好明天能不能过。我觉得,不要受制于人的要求是有点高,能做到不完全受制于人已经不错了。

主题:

关于NIO的基本知识在(系列17)记录过了,继续来了解下Buffer

Buffer API:

复制代码
int capacity()//返回此缓冲区的容量。 
Buffer clear()//清除此缓冲区。 
Buffer flip()//反转此缓冲区。 
boolean hasRemaining()//判断在当前位置和限制之间是否有任何元素。 
abstract  boolean isReadOnly()//判断此缓冲区是否为只读缓冲区。 
int limit()//返回此缓冲区的限制。 
Buffer limit(int newLimit)//设置此缓冲区的限制。 
Buffer mark()//在此缓冲区的位置设置其标记。 
int position()//返回此缓冲区的位置。 
Buffer position(int newPosition)//设置此缓冲区的位置。 
int remaining()//返回当前位置与限制之间的元素数量。 
Buffer reset()//将此缓冲区的位置重新设置成以前标记的位置。 
Buffer rewind()//重绕此缓冲区。
复制代码

直接看源码,关于其中的flip和clear方法在系列17中详细学习了。

复制代码
public abstract class Buffer {

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;    // 一个备忘位置
    private int position = 0; // 位置,下一个要被读或写的元素的索引,根据它来决定读哪个位置
    private int limit; // 上界,缓冲区的第一个不能被读或写的元素。
    private int capacity; // 缓冲区容量。缓冲区创建时被设定,并且永远不能被改变。

    // 初始化
    Buffer(int mark, int pos, int lim, int cap) {    // package-private
    if (cap < 0)
        throw new IllegalArgumentException();
    this.capacity = cap;
    limit(lim);
    position(pos);
    if (mark >= 0) {
        if (mark > pos)
        throw new IllegalArgumentException();
        this.mark = mark;
    }
    }
    
    public final int capacity() {
    return capacity;
    }

    public final int position() {
    return position;
    }

    public final Buffer position(int newPosition) {
    if ((newPosition > limit) || (newPosition < 0))
        throw new IllegalArgumentException();
    position = newPosition;
    if (mark > position) mark = -1; // 因为重新设置position,mark可能超过它,索性把mark还原
    // 返回设置好后新的自己
    // 这种返回自己的方式可以实现支持级联调用,比如buffer.mark().position(5).reset( );
    return this; 
    }

    public final int limit() {
    return limit;
    }

    public final Buffer limit(int newLimit) {
    if ((newLimit > capacity) || (newLimit < 0))
        throw new IllegalArgumentException();
    limit = newLimit;
    // limit的设置牵涉到下面两个:position和mark
    if (position > limit) position = limit;
    if (mark > limit) mark = -1;
    return this;
    }

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

    public final Buffer reset() {
        int m = mark;
    if (m < 0)
        throw new InvalidMarkException();
    position = m;// 把position设置到mark的位置,下一次读数据的时候就可以,从mark的位置读起了。
    return this;
    }

    public final Buffer clear() {
    position = 0; // position清零
    limit = capacity; // limit初始化
    mark = -1; // mark初始化
    // 三步操作这个Buffer又重生了。可以继续用了。下一次写入,就是覆盖即可。
    // 注意clear方法返回了自己,因为clear方法没有真正意义上clear自己的内容,如果这时候我们操作返回的buffer,这个buffer是有内容的。
    return this; 
    }

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

    public final Buffer rewind() {
    position = 0;// 和clear()操作不同的是少了limit初始化,如此即可实现对这个buffer的重读
    mark = -1;
    return this;
    }
    //返回当前位置与限制之间的元素数量。
    public final int remaining() {
    return limit - position;
    }
    //判断在当前位置和限制之间是否有任何元素。 
    public final boolean hasRemaining() {
    return position < limit;
    }
    // 所有的缓冲区都是可读的,但并非所有都可写。
    public abstract boolean isReadOnly();
    // 后面还有nextGetIndex(),nextGetIndex(int nb) 等方法,因为是不是对外提供的方法,就不进一步介绍了。
}
复制代码

ByteBuffer的API:

1,HeapByteBuffer中实现了抽象类ByteBuffer中为实现的方法。

2,ByteBuffer中的get set 方法就是对一个数组的操作。

get的四个方法:

get();
get (int index);
get(byte[] dst);
get(byte[] dst, int offset, int length);

前两个方法比较好理解,返回的是取得的内容,后面两个方法是将此缓冲区的字节传输到给定的目标数组中。

来看下源码:

复制代码
public ByteBuffer get(byte[] dst) {
    return get(dst, 0, dst.length);
}
    
public ByteBuffer get(byte[] dst, int offset, int length) {
    checkBounds(offset, length, dst.length);
    if (length > remaining())
        throw new BufferUnderflowException();
    int end = offset + length;
    // 最后还是一个个拿
    for (int i = offset; i < end; i++)
        dst[i] = get();
    return this;
}
复制代码

put方法API:

abstract  ByteBuffer put(byte b)
ByteBuffer put(byte[] src)
ByteBuffer put(byte[] src, int offset, int length)
ByteBuffer put(ByteBuffer src)
abstract  ByteBuffer put(int index, byte b)

 

压缩方法:

public abstract ByteBuffer compact( );

看下图,使用前:

使用后:

调用compact()的作用是丢弃已经释放的数据,保留未释放的数据,并使缓冲区对重新填充容量准备就绪。但是需要注意的时候如果我们需要马上读取数据的时候还是需要先调用flip()方法,把position置0。

 

有点发烧,预计的内容写不上去,先停一下,下次补上去。

 

让我们继续前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不会成功。
共勉。

posted on   每当变幻时  阅读(2283)  评论(4编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述

导航

< 2012年12月 >
25 26 27 28 29 30 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示