NIO源码解析之buffer

我们先从ByteBuffer的allocate分配字节数组看起

我们发现这个方法接受一个capacity参数,也就是容量参数

返回了一个HeapByteBuffer(capacity,capacity)对象,我们看下这个类 

他通过传入的容量值够早了一个

mark为-1  pos为0  lim为cap 大小为cap的字节数组   偏移量为0

可以看出分配的buffer是在heap区域的, 它调用了父类的构造方法,它的父类是ByteBuffer

我们看下:

这里主要完成了数组单位的的赋值

 我们先看下它的父类Buffer的构造方法:

这里进行判断传入的值是否符合要求

我们看下传入的参数的方法 

 我们发现里面有两个方法是limit和position

这两个方法在这里的作用就是判断传入的limit值和position的值是否合法 

总结这个构造方法就是:返回一个在堆内存分配的相应类型的缓冲区,并且进行了一系列的传入参数合法判断。

剩下的看这位博主的就好了

https://blog.csdn.net/u010412719/article/details/52775637 

这里要说一个问题,看网上最常见的图

这个图真的太容易误导人了,首先我们知道一个缓存空间底层是通过字节数组实现的,那么这个字节数组创建时相当于这样的语句new ByteBuffer【capacity】,那么这个数组长度为capacity,但是索引不应该是capacity。,因为索引无法达到这个长度,换句话说这个图的capacity改为capacity-1才对

那么应该这么定义:position的值是下一个要被写入或者被读的空间,它的值就是所有被读取或者被写入的长度(从0开始)

                                 limit的值:是限制空间(能读或者能写多少字节)的长度

                                 capacity的值:是总长度,不应该讲为索引

那么我们看下它的读取和写入是如何实现的就能更深的理解这个东西了

put(int i)方法介绍

下面来看IntBuffer类中的put方法

    public abstract IntBuffer put(int i);

    public abstract int get(int index);

在IntBuffer类中put、get方法都是抽象的。 
有了上面allocate方法的过程分析,我们知道IntBuffer buffer = IntBuffer.allocate(cap) 
中的buffer实际上是父类的引用指向的是子类的对象。当我们使用buffer.put(value)/buffer.get(). 
实际上是调用子类HeapIntBuffer类中的put/get方法,这就是多态。在Java中相当重要的一个特征。

HeapIntBuffer类中put方法的实现如下:

    public IntBuffer put(int x) {

        hb[ix(nextPutIndex())] = x;
        return this;

    }

put方法实现的思想就是:将值存储在position位置即可。

这里涉及到两个新的函数,分别为:

1、nextPutIndex(),函数功能:简单来说就是返回下一个要写入元素的索引位置(即当前position值),并将position进行加一操作。

2、ix(int i):偏移offset个位置

这两个函数的实现如下:

    //函数功能:首先检查当前的position是否小于limit,如果小于则存储,否则抛异常。
    final int nextPutIndex() {                          // package-private
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }
    //函数功能:偏移offset个位置
    protected int ix(int i) {  
        return i + offset;
    }

我们主要看着两个方法:如果从一开始读或者写的话那么偏移量为0,我们只看第一个方法:

判断条件为:position>=limit 这里用的是>=不是>就很好说明了limit只是一个长度

如果position等于了limit,那么此时position已经超出界限了,不能读写

注意:limit和capacity都是长度而不是索引,我们每次得到position时会++,这样当position达到最终写完长度的索引时,它刚好还加了1,那么我们切换读模式的时候直接将position赋值给limit就行了。

3、get()方法介绍

看完了put方法,接下来来看下get方法

函数的功能:取得Buffer中position位置所指向的元素。

    //函数功能:获取buffer中position所指向的元素。
    public int get() {
        return hb[ix(nextGetIndex())];
    }
    //函数功能:获取buffer中索引为i位置的元素
    public int get(int i) {
        return hb[ix(checkIndex(i))];
    }

在get()方法中也涉及到两个另外的函数:

1、nextGetIndex(),函数功能:返回下一个读取的元素的索引位置(即position值)

2、ix(int i)

    final int nextGetIndex() {                          // package-private
        if (position >= limit)
            throw new BufferUnderflowException();
        return position++;
    }
    //将position向右移动nb个位置,这个函数目前还没有看见在哪里得到的应用
    final int nextGetIndex(int nb) {                    // package-private
        if (limit - position < nb)
            throw new BufferUnderflowException();
        int p = position;
        position += nb;
        return p;
    }

这个方法和哪个方法一样。也是操作position

猜你喜欢

转载自blog.csdn.net/Sunmeok/article/details/81783143