美文网首页
ByteBuffer之HeapByteBuffer源码分析

ByteBuffer之HeapByteBuffer源码分析

作者: 无聊之园 | 来源:发表于2019-05-12 17:22 被阅读0次

    ByteBuffer是一个抽象类,继承于Buffer。

    ByteBuffer有两个实现类:
    HeapByteBuffer:对应,ByteBuffer的alloccate方法。
    DirectByteBuffer:对应,ByteBuffer的allocateDirect方法。

    先分析HeapByteBuffer。
    HeapByteBuffer是在在java堆的分配内存,就像普通的ArrayList或HashMap一样。

    其父类Buffer有几个重要的成员变量

    // 标记位,reset后position会跳到这个位置,进行重复读
    private int mark = -1;
    // 实际读或写的位置
        private int position = 0;
    // 有效数据的位置,读的时候,limit是有效数据,写的时候,limit是容量
        private int limit;
    // 容量
        private int capacity;
    

    ByteBuffer的变量

    // 真正存储数据的数据
    final byte[] hb;  
    // 偏移量,byteBuffer可以控制从哪一个位置开始存储数据
    final int offset;
    

    ByteBuffer.allocate方法

    public static ByteBuffer allocate(int capacity) {
            if (capacity < 0)
                throw new IllegalArgumentException();
            return new HeapByteBuffer(capacity, capacity);
        }
    HeapByteBuffer(int cap, int lim) {            // package-private
     // 初始化:mark = -1, position=0,limit=capacity,offset偏移量为0
            super(-1, 0, lim, cap, new byte[cap], 0);
            /*
            hb = new byte[cap];
            offset = 0;
            */
        }
    ByteBuffer(int mark, int pos, int lim, int cap,   // package-private
                     byte[] hb, int offset)
        {
            super(mark, pos, lim, cap);
            this.hb = hb;
            this.offset = offset;
        }
    

    put方法:写入数据

    public ByteBuffer put(byte[] src, int offset, int length) {
            // 检查是否越界
            checkBounds(offset, length, src.length);
            // 可用位置是否足够
            if (length > remaining())
                throw new BufferOverflowException();
            // 复制byte数组进hb
            System.arraycopy(src, offset, hb, ix(position()), length);
            // position为put数据后的位置
            position(position() + length);
            return this;
        }
      public final int remaining() {
            return limit - position;
        }
    

    flip:把写入数据的模式切换为读取数据

    public final Buffer flip() {
            // position为已有数据的长度,limit指向它,或者说有效数据的长度
            limit = position;
            // 下一个读取数据的位置,从0开始
            position = 0;
            mark = -1;
            return this;
        }
    

    get:读取数据

    public ByteBuffer get(byte[] dst, int offset, int length) {
            checkBounds(offset, length, dst.length);
            if (length > remaining())
                throw new BufferUnderflowException();
             // 复制hb的数据到传入擦书dst中,ix方法是加上偏移量,如果有偏移量的话,数据存储的起始位置就是position + offset
            System.arraycopy(hb, ix(position()), dst, offset, length);
            position(position() + length);
            return this;
        }
    // 加上偏移量
    protected int ix(int i) {
            return i + offset;
        }
    

    mark:标记重读的位置

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

    reset:重mark标记的地方重读

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

    compact:压缩数据,把已读数据清除掉。position指向有效数据的位置,也就是从读模式切换为写模式,可以进行put了

    public ByteBuffer compact() {
            // 移动数组位置,把已读数据清除掉
            System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
            // 重置position位置为有效数据的长度
            position(remaining());
            // limit为capacity的大小
            limit(capacity());
            // 丢弃mark,mark = -1
            discardMark();
            return this;
        }
    

    clear:重置为新的Buffer,重新进行写数据

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

    slice:切一个子buffer,切掉已读数据部分,hb还是原来的hb,只是偏移量移过已经读过的数据

     public ByteBuffer slice() {
            return new HeapByteBuffer(hb,
                                            -1,
                                            0,
                                            this.remaining(),
                                            this.remaining(),
                                            this.position() + offset);
        }
    

    duplicate : 复制一份一模一样的buffer

    public ByteBuffer duplicate() {
            return new HeapByteBuffer(hb,
                                            this.markValue(),
                                            this.position(),
                                            this.limit(),
                                            this.capacity(),
                                            offset);
    

    asCharBuffer:bytebuffer提供了转成其他类型buffer的方法,并非真正的转,而是保证了byte数组的CharBuffer,直到get或put操作的时候才会将byte转成对应的类型

    public CharBuffer asCharBuffer() {
            int size = this.remaining() >> 1;
            int off = offset + position();
            return (bigEndian
                    ? (CharBuffer)(new ByteBufferAsCharBufferB(this,
                                                                   -1,
                                                                   0,
                                                                   size,
                                                                   size,
                                                                   off))
                    : (CharBuffer)(new ByteBufferAsCharBufferL(this,
                                                                   -1,
                                                                   0,
                                                                   size,
                                                                   size,
                                                                   off)));
        }
    // 虽然是charBuffer,但是实际维护的数组还是byte数组
    ByteBufferAsCharBufferB(ByteBuffer bb,
                                         int mark, int pos, int lim, int cap,
                                         int off)
        {
            super(mark, pos, lim, cap);
            this.bb = bb;
            offset = off;
        }
    // 直到操作数据的才将byte转成对应的类型
    public char get() {
            return Bits.getCharB(bb, ix(nextGetIndex()));
        }
    

    相关文章

      网友评论

          本文标题:ByteBuffer之HeapByteBuffer源码分析

          本文链接:https://www.haomeiwen.com/subject/wkicaqtx.html