java.nio.Buffer缓冲区源码解析

1.Buffer缓冲区的原理图


2.常用的变量

//临时备忘位置变量
    private int mark = -1;
	/**
	 * 在写模式下,position从0开始写,一直可以写到capacity-1。
	 * 在读模式下,position从某个位置去读,如果从写切换到读,那么position被设置为0。
	 */
    private int position = 0;
	/**
	 * 缓冲区可读可写的容量,可读可写limit最大情况下,limit=capacity
	 */
    private int limit;
	/**
	 * 缓冲区的总容量
	 */
    private int capacity;

    //指向缓冲区的地址
    long address;

3.构造器

//创建一个指定mark、pos、limit、capacity参数的构造器
    Buffer(int mark, int pos, int lim, int cap) {       
		//如果缓冲区的初始化容量小于0,那么抛出非法参数异常。
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
		//设置缓冲区的初始化容量
        this.capacity = cap;
		//设置缓冲区的限制,设置最新的缓冲区Buffer
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("
                                                   + mark + " > " + pos + ")");
            this.mark = mark;
        }
    }

	/**
     * 设置缓冲区的限制。
	 * 如果position>limit,那么重新设置新的limit。
	 * 如果mark>limit,那么最新的limit将会被抛弃。
     */
    public final Buffer limit(int newLimit) {
		//如果输入参数newLimit大于缓冲区最大容量capacity或者小于0,那么抛出非法参数异常。
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
		//设置输入参数newLimit为缓冲区最新的limit。
        limit = newLimit;
		//如果开始读写的位置大于了已存放数据的容量,那么将读写位置设置为已存放数据的容量。
        if (position > limit) position = limit;
		//如果临时备忘位置大于已存放数据的容量,那么将mark设置为-1。
        if (mark > limit) mark = -1;
		//返回当前的缓冲区Buffer
        return this;
    }
	
	/**
     * 设置读写的开始位置。
	 * 如果mark>position,那么position这个变量将会被抛弃。
     */
    public final Buffer position(int newPosition) {
		//如果输入参数newPosition大于可读可写的最大容量或者newPosition小于0,那么抛出非法参数异常。
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
		//设置输入参数newPosition作为最新的读写开始位置。
        position = newPosition;
		//如果临时备忘位置mark大于position,设置mark为-1。
        if (mark > position) mark = -1;
		//返回当前的缓冲区Buffer
        return this;
    }

4.常用方法

/**
     * 获取当前缓冲区Buffer的最大容量
     */
    public final int capacity() {
        return capacity;
    }

    /**
     * 获取当前缓冲区Buffer的读写开始位置
     */
    public final int position() {
        return position;
    }

    /**
     * 获取当前缓冲区Buffer的读写的最大容量
     */
    public final int limit() {
        return limit;
    }

    /**
     * 设置当前缓冲区的备忘变量为position
	 * 返回当前最新缓冲区Buffer
     */
    public final Buffer mark() {
        mark = position;
        return this;
    }

    /**
     * 将缓冲区Buffer的位置position设置为以前临时备忘变量mark存储的位置。
     */
    public final Buffer reset() {
		//获取当前临时备忘变量mark
        int m = mark;
		//如果临时备忘变量m小于0,那么抛出无效的标记异常。
        if (m < 0)
            throw new InvalidMarkException();
		//设置当前缓冲区读写开始位置为备忘变量mark
        position = m;
		//返回当前最新缓冲区Buffer
        return this;
    }

    /**
     * 清除缓冲区
     */
    public final Buffer clear() {
		//设置读写开始位置position为0
        position = 0;
		//设置读写的最大容量limit为缓冲区最大容量capacity
        limit = capacity;
		//设置临时备忘变量值为-1
        mark = -1;
		//返回当前最新缓冲区Buffer
        return this;
    }

    /**
     * 反转此缓冲区
	 * 在进行写完去读的时候使用
     */
    public final Buffer flip() {
		//将读写的最大容量设置为当前的位置
        limit = position;
		//将position设置为0
        position = 0;
		//设置临时备忘变量为-1
        mark = -1;
		//返回当前最新的缓冲区Buffer
        return this;
    }

    /**
     * 重绕此缓冲区
	 * 在通道写入或者获取之前调用
     */
    public final Buffer rewind() {
		//设置当前位置为0
        position = 0;
		//将临时备忘变量设置为-1
        mark = -1;
		//返回当前最新的缓冲区Buffer
        return this;
    }

    /**
     * 返回当前的缓冲区Buffer的剩余元素的数量
     */
    public final int remaining() {
        return limit - position;
    }

    /**
     * 返回当前的缓冲区中是否有元素
	 * 如果有就返回true
	 * 如果没有就返回false
     */
    public final boolean hasRemaining() {
        return position < limit;
    }

    /**
     * 当前的缓冲区是否只读
	 * 如果是就返回true
	 * 如果不是就返回false
     */
    public abstract boolean isReadOnly();

    /**
     * 当前的缓冲区是否可以访问底层的数组
     */
    public abstract boolean hasArray();

    /**
     * 返回当前缓冲区的底层实现数组
     */
    public abstract Object array();

    /**
     * 返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量(可选操作)。
     */
    public abstract int arrayOffset();

    /**
     * 此缓冲区是否为直接缓冲区
     */
    public abstract boolean isDirect();


    // -- Package-private methods for bounds checking, etc. --

    /**
     * 获取当前位置的下一个位置
     */
    final int nextGetIndex() {   
		//如果当前位置大于等于limit,抛出缓冲区向下溢出异常。
        if (position >= limit)
            throw new BufferUnderflowException();
		//返回当前位置的下一个位置
        return position++;
    }

	/**
     * 当前位置增加指定参数的长度
	 * 返回未增加前的位置
     */
    final int nextGetIndex(int nb) {  
		//如果limit值减去当前位置值小于nb,抛出缓冲区向下溢出异常。
        if (limit - position < nb)
            throw new BufferUnderflowException();
        int p = position;
        position += nb;
        return p;
    }

    /**
     * 自增当前位置
     */
    final int nextPutIndex() {                          // package-private
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }

	/**
     * 当前位置增加指定参数的长度
	 * 返回增加之前的位置
     */
    final int nextPutIndex(int nb) {                    // package-private
        if (limit - position < nb)
            throw new BufferOverflowException();
        int p = position;
        position += nb;
        return p;
    }

    /**
     * 检查参数i是否小于limit
     */
    final int checkIndex(int i) {                       // package-private
        if ((i < 0) || (i >= limit))
            throw new IndexOutOfBoundsException();
        return i;
    }
	
	/**
     * 检查参数i是否小于limit-指定的参数
     */
    final int checkIndex(int i, int nb) {               // package-private
        if ((i < 0) || (nb > limit - i))
            throw new IndexOutOfBoundsException();
        return i;
    }

	//返回临时备忘变量值
    final int markValue() {                             // package-private
        return mark;
    }

	//清空缓冲区的容量
    final void truncate() {                             // package-private
        mark = -1;
        position = 0;
        limit = 0;
        capacity = 0;
    }

	//抛弃临时备忘变量
    final void discardMark() {                          // package-private
        mark = -1;
    }

5.阅读总结

①在写完去读的时候,使用flip方法,特点就是将读的容量limit设置为写的position,将读的开始位置position设置为0,将mark设置为-1(至于为什么,可以参考前面的原理图进行思考)。

②在读完去写的时候,使用clear方法,特点就是将position设置为0,写的limit值设置为当前缓冲区的capacity,将mark设置为-1。

③至于mark和reset方法,它们的作用就是将position恢复到原位。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值