Buffer缓存区

Buffers阅读笔记

一、简介

这是一个缓存区的抽象类,真正的数组存储在ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、CharBuffer、DoubleBuffer、FloatBuffer

二、继承关系图

在这里插入图片描述

  • 由上图(可以放大)可以看出,Buffer是一个抽象类,有很多子类去实现,但是他们也都是抽象类,但是最终实现的是HeapxxxBuffer。Byte开头的因为特殊处理字节,所以会有一个Bits协助

三、存储结构

  • 自身没有存储结构,由抽象子类xxxBuffer有一个存储数组(同类型)

四、源码分析

内部类
属性
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;// 标记,用于reset把position修改为mark,如果mark=-1或未定义会抛异常
private int position = 0;// 当前位置,表示读取或写入的位置
private int limit;// 读取/写入的限制,当前索引开始及以后不可读取和写入
private int capacity;// 容量。代表该缓存中的容量

static final int SPLITERATOR_CHARACTERISTICS =
        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;

long address;
构造
// 初始化构造器,同时初始化核心的4个属性,注意此构造是采用的默认修饰,所以是不支持直接实例化
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;
    }
}
主要方法
1、读取4大属性
  • 读取 4 大属性

    public final int capacity() {return capacity;}
    public final int position() {return position;}
    public final int limit() {return limit;}
    // package-private,仅支持同包及本类访问
    final int markValue() {return mark;}
    
2、单个操作4大属性
  • 单个操作 4 大属性

    /**
     * capacity 仅在实例化的时候设置 
     */
    
    /**
     * 设置position,涉及到逻辑处理
     */
    public final Buffer position(int newPosition) {
        // 边界效验
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        // 设置
        position = newPosition;
        // 1. mark 大于 position 直接设置为-1,reset()就会抛出异常(mark小于0)
        if (mark > position) mark = -1;
        return this;
    }
    /**
     * 设置limit,涉及到逻辑处理
     */
    public final Buffer limit(int newLimit) {
        // 边界效验
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        // 设置
        limit = newLimit;
        // 1. position 大于limit,则直接设置position为limit
        // 也代表读写操作都会抛出异常
        if (position > limit) position = limit;
        // 2. mark 大于 limit直接设置为-1,reset()就会抛出异常(mark小于0)
        if (mark > limit) mark = -1;
        return this;
    }
    
    /**
     * 设置mark,在当前位置(position)设置标记
     */
    public final Buffer mark() {
        mark = position;
        return this;
    }
    
3、缓冲区4属性处理
  • 缓冲区属性处理

    /**
     * 还原缓冲区的数据
     * 还原一切状态
     */
    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;
    }
    /**
     * 反转此缓冲区
     * 适合用于在缓冲区写入数据,然后,再从缓冲区读取数据(不用考虑limit限制)
     * 也就是使缓冲区为“重新读取”已包含的数据做好准备,他使限制保持不变,讲位置设置为0
     * 类似substring截取
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }
    /**
     * 重绕缓冲区,将当前位置设置为0,并丢弃标记
     * 适合用于重新读取/写入缓冲区时,(前提是设置了适当的limit限制)
     * 重新读取重新吸入的时候可用
     */
    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }
    
4、判断剩余量和底层数组
  • 判断剩余量和底层数组

    /**
     * 判断是否还有剩余可读写容量
     */
    public final boolean hasRemaining() {
        return position < limit;
    }
    /**
     * 抽象方法:是否是只读(非直接缓存(JVM中间缓存区)支持读写,但是直接缓存(内存)只支持读)
     */
    public abstract boolean isReadOnly();
    /**
     * 抽象方法:JVM缓冲区是否有数组
     */
    public abstract boolean hasArray();
    /**
     * 抽象方法:是否是直接缓存区(直接跳过JVM中间缓存区)
     */
    public abstract boolean isDirect();
    
5、获取剩余容量和底层数组
  • 获取剩余容量和底层数组

    /**
     * 获得剩余可读写的容量
     */
    public final int remaining() {
        return limit - position;
    }
    /**
     * 抽象方法,获取数组
     */
    public abstract Object array();
    /**
     * 获取数组的偏移量
     */
    public abstract int arrayOffset();
    
6、其他package-private可用方法
  • 其他默认修饰方法

    /**
     * 所有子类get使用,使当前位置(position)+ 1,并返回原position索引
     */
    final int nextGetIndex() {                          // package-private
        if (position >= limit)
            throw new BufferUnderflowException();
        return position++;
    }
    
    /**
     * 所有子类get使用,使当前位置(position)+ nb,并返回原position索引
     */
    final int nextGetIndex(int nb) {                    // package-private
        if (limit - position < nb)
            throw new BufferUnderflowException();
        int p = position;
        position += nb;
        return p;
    }
    
    /**
     * 同get一样逻辑
     * 所有子类put使用,使当前位置(position)+ 1,并返回原position索引
     */
    final int nextPutIndex() {                          // package-private
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }
    
    /**
     * 同get一样逻辑
     * 所有子类put使用,使当前位置(position)+ nb,并返回原position索引
     */
    final int nextPutIndex(int nb) {                    // package-private
        if (limit - position < nb)
            throw new BufferOverflowException();
        int p = position;
        position += nb;
        return p;
    }
    
    /**
     * 检查 i 是否可读写
     */
    final int checkIndex(int i) {                       // package-private
        if ((i < 0) || (i >= limit))
            throw new IndexOutOfBoundsException();
        return i;
    }
    
    /**
     * 检查 i 是否可读写,nb代表每次读写的位,一次读写的位超出limit则边界异常
     */
    final int checkIndex(int i, int nb) {               // package-private
        if ((i < 0) || (nb > limit - i))
            throw new IndexOutOfBoundsException();
        return i;
    }
    
    /**
     * 读取当前mark值
     */
    final int markValue() {                             // package-private
        return mark;
    }
    
    /**
     * 限制读写操作,直接所有设置最低值
     */
    final void truncate() {                             // package-private
        mark = -1;
        position = 0;
        limit = 0;
        capacity = 0;
    }
    
    /**
     * 丢弃原mark,直接设置为-1
     */
    final void discardMark() {                          // package-private
        mark = -1;
    }
    
    /**
     * off 开始索引位
     * len 每次读写操作量
     * size 此数组容量长度
     * 效验本次读取是否超出边界
     */
    static void checkBounds(int off, int len, int size) { // package-private
        if ((off | len | (off + len) | (size - (off + len))) < 0)
            throw new IndexOutOfBoundsException();
    }
    
补充

五、总结

抽象类 ShortBuffer、LongBuffer、IntBuffer、DoubleBuffer、FloatBuffer的所有函数基本上是一样的,只是存储的接口不同。所以操作有点却别,但是函数一样。

charBuffer由于需要操作字符,所以比上面的会多一些例如append,charAt、subDequence函数

ByteBuffer因为也比上面多,例如_get、_put、putXXX、getXXX、asXXXBuffer等

heapXXXBuffer的实现类同上,也是相似和不同之处。原因请看后面的源码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值