缓冲区的概念以及java.nio.Buffer

[b]基本概念[/b]

所谓缓冲区buffer,就是“临时存贮区”的意思,是暂时存放输入输出数据的一段内存。

要使用缓冲区,肯定要先分配内存,如下:
byte[] buf = new byte[10];

这里牵涉到一个概念: 容量capacity,缓冲区的大小,分配的内存的大小,
即上面的数字10。这个大小是不可变的。为什么说不可变呢?因为,内存都分配好了,
哪还能变,如果要改变大小,就要重新分配内存,重新分配内存的话,就是新的缓冲区了,
就不是本来的那个了。:)

内存分配好了,再看怎么用。

既然是临时存储,那么缓冲区的使用过程就应该是:放入数据,然后取出数据,
由此可得,缓冲区的基本操作是put和get。

比如要往里面放数据,就put!

但放到哪里呢?
这个时候,就需要一个概念:位置position,即当前的操作位置。
比如这样:
buf[0] = (byte)2;(这里的赋值操作相当于put)
这就表示把数据2放到了0这个位置,这里的position即为0。

如果没有这个position,就只能随处乱put了。就像“禁止随处大小便”一样,
随处乱put也是不行的。随处大小便出来的东西你是不会再要的,这尚且不行,
何况put的数据后面你还要再找回来,那当然就更不能乱来了。至于取数据get,
当然完全类似,哪儿put的哪儿get就是了。

再看还需要什么属性和操作。

有个计算题,说:一辆公交车,车上有22人,到站停车,上来10个,下去15;又停一次,
上来8,下去10个;又停一次,上来18,下去20;又停一次,上来66,下去1个。
请问,公交车停了几次?相信这个笑话大家听说过了。

和这个笑话类似,往缓冲区里放数据:
put一次,再put一次,再put一次,…put了好多次之后,请问,总共put了多少次?

实际上,和公交车问题的情形相反,问put多少次,意义应该不是很大。更有意义的问题是,
put了多少数据进去?这些数据都put到哪里去了?
那put了多少数据呢?没有记录的话,还是不知道。所以,
还是要记录下来,就用dataLength来记录吧。至于put到了哪里,那肯定是从buf开始的地方开始的。

那么现在总结一下缓冲区中的概念:
1. 缓冲区的容量capacity;
2. 缓冲区存取操作put/get;
3. 操作的位置position;
4. 已存入的数据的多少dataLength。

至此,缓冲区的基本概念算是基本介绍完了。

下面介绍一下java.nio.Buffer类对buf的实现。


[b]java.nio.Buffer类对buf的实现[/b]

Buffer类里面,属性字段有:
capacity (容量):缓冲区的容量是其空位的数量。缓冲区的容量永远不会为负并且从不会更改。

position (位置):缓冲区的位置是下一个要读取或写入的元素的索引。
缓冲区的位置永远不会为负,并且永远不会大于其限制。

limit (限制):缓冲区的限制是不应读取或写入的第一个元素的索引。
缓冲区的限制永远不会为负,并且永远不会大于其容量。

mark (标记):缓冲区的标记是在调用reset 方法时其位置将被重置到该mark位置。
如果定义的标记后,位置(position)或限制(limit)调整为小于标记的值时,
该标记将被丢弃。如果未定义标记,则调用 reset 方法将导致抛出InvalidMarkException。
这几者之间的关系式如下:
0 <= 标记 <= 位置 <= 限制 <= 容量


对比基本概念和java中Buffer的实现可以看出:
capacity的意义是相同的;
position的意义是相同的;

不同的是dataLength和limit,至于mark,感觉不到什么用,不讲了。

看limit的定义,limit是一个位置索引,表示可操作和不可操作区域的分界,
position和limit之间的距离指示了可读取/存入的字节数。
在这里,java.nio.Buffer引入了新的概念:区域的概念,可操作区域和不可操作区域。

可操作区域:在put的时候,表示还有多少空间可写入,在get的时候,表示还有多少数据可读取。
注意:可操作区域,在put和get的时候,表示的含义是不同的,一个表示可用空位的多少,
一个表示可用数据的多少。在put之后,要有一个转换的过程,之后才能从缓冲区中get数据。
boolean hasRemaining()
int remaining()
这两个方法就是用来获得可读取/存入的字节数,即可操作区域的大小。

不可操作区域:不可操作区域就是字面上的意思,即不可操作的区域。在put时,
整个buf都可以写入,因此,不可操作区域是空的;在get的时候,不可操作区域是没有数据的区域。

limit:就是上述的可操作区域和不可操作区域的分界线。


上面解释了limit的基本概念,现在再详细地看一下limit和其他几个属性间的关系:


在put写入的时候,可用空间表示还没数据的部分,则limit固定的为capacity,
capacity-limit表示为不可用的空间,limit-position表示可用空间;

在get读取的时候,可用空间表示缓冲区已有数据的部分,前半部分limit-position表示可用数据,
后半部分capacity-limit表示不能操作,因为那里没有数据;

在put和get操作之间,因为可用空间上有无数据的含义不相同,需要有一个flip操作,
来更新limit,进而更新可用空间的的含义,更新之后才能操作数据。

再看基本概念中的dataLength和java.nio.Buffer中limit概念的区别:

Buffer类中引入了新的概念:区域的概念,可操作区域和不可操作区域,
limit表示这两个区域的分界线,很直观。在区域里,limit配合position就可以得到要用到的数据。

dataLength是一个数字,只表示缓冲区中数据的多少,很不形象啊。

对比dataLength和limit,limit更加形象,直接把缓冲区分成两个部分,
每个部分的含义都很清楚。limit不爽的地方是,在写读转换的时候,要flip一下,
且只能flip一下,flip多了还会出问题。

再看mark,感觉这个好像没什么用处,跟个记录position的临时变量一样,
不知道java为什么非要这个操作不可。

方法

操作分两种:
相对操作 :操作读取或写入从当前位置开始的一个或多个元素,然后将该位置增加传输的元素的数量。
绝对操作 :操作采用显式元素索引,不会影响位置。
缓冲区基本概念中,使用的是绝对操作,这里的相对操作,只是增加使用的便利而已。

基本概念解释清楚,操作方法应该就很好理解了,就不详细解释了,写得太累了,
操作方法请参照[url]http://www.blogjava.net/killme2008/archive/2008/02/22/181357.html[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值