美文网首页
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