美文网首页JDK源码
java.nio.Buffer源码解析

java.nio.Buffer源码解析

作者: sunpy | 来源:发表于2018-02-27 21:39 被阅读8次

所属包

package java.nio;

继承与实现关系

public abstract class Buffer

Buffer缓冲区原理图

20180130141414174.png

常用的变量

    //临时备忘位置变量  
    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;  

构造器

    //创建一个指定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;  
        }  
    }  

方法

limit方法:设置缓冲区的限制。

    /** 
     * 设置缓冲区的限制。 
     * 如果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;  
    }  

position方法:设置读写的开始位置。

    /** 
     * 设置读写的开始位置。 
     * 如果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;  
    }  
    /** 
     * 获取当前缓冲区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;  
    }  

阅读总结

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

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

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


---------------------------该源码为jdk1.7版本的

相关文章

网友评论

    本文标题:java.nio.Buffer源码解析

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