《Java源码分析》:Java NIO 之 Buffer
在上篇博文中,我们介绍了Java NIO 中Channel 和Buffer的基本使用方法,这篇博文将从源码的角度来看下Buffer的内部实现。
在Java API文档中,对Buffer的说明摘入如下:
Buffer:是一个用于特定基本数据类型的容器。这里的特定基本数据类型指的是:除boolean类型的其他基本上数据类型。
缓冲区是特定基本数据类型元素的线性有限序列。除内容外,缓冲区饿基本属性还包括三个重要的属性,如下:
1、capacity(容量):表示Buffer容量的大小。
2、limit(限制):是第一个不应该读取或写入的元素的索引。缓冲区的限制不能为负数,并且不能大于其容量。
3、position(位置):表示下一个要读取或写入的元素的索引。缓冲区的位置不能为负数,并且不能大于其限制。
刚看文档的时候,可能对limit和position的含义不是太能理解。这个我们看完源码之后,就会懂了哈,不急。
不过在看源码之前,可以提前来通过画图的方式来解释下limit 和 position。
在Buffer中有两种模式,一种是写模式,一种是读模式。
有了上图应该比较好理解position和limit的含义了。
下面就看下Buffer的源代码了。由于Buffer有很多子类,这里主要以IntBuffer为例。
Buffer的几个重要属性
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;//位置
private int limit;//限制
private int capacity;//容量
这几个属性就也就是我们上面说到的position、limit、capacity,最后还有一个mark。
Buffer的构造方法
//构造函数,根据指定的参数来初始化Buffer特定的属性
//此构造函数时包私有的
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;
}
}
构造函数中的逻辑相当简单,就是一个初始化,不过在里面包括的相关的有效性检查。
要注意的是此构造函数是包私有的。
可能有人像我一样,会有这样一个疑问:Buffer类是抽象类,为什么会有构造函数呢?
由于关于抽象类中有构造函数,自己也是第一次见到。因此查阅的相关资料。发现如下:
1、抽象类是可以有构造函数的。但很多人认为,构造函数用于实例化一个对象(或建立一个对象的实例),而抽象类不能被实例化,所以抽象类不应该有公共的构造函数。但不应该有“公共”的构造函数,和不应该有构造函数,这是两个不同的概念,所以,如果抽象类需要构造函数,那么应该声明为“protected”。
2、既然抽象类是可以,甚至有时候应该有构造函数,那抽象类的构造函数的作用是什么?我觉得至少有两个:
(1)初始化抽象类的成员;
(2)为继承自它的子类使用。
在Buffer这个抽象类中我们可以明显的感受到以上两点的作用。
3、即使我们声明一个没有构造函数的抽象类,编译器还会为我们生成一个默认的保护级别的构造函数。子类实例化时(不管是否为带参构造)只会调用所有父类的无参构造函数,而带参构造必须通过显式去调用