Java buffer为什么要用flip()和clear()方法
Bytebuffer:
position和limit两个变量最重要:
在写的时候position表示开始写的位置,limit表示能写的最大位置。
在读的时候position表示开始读取的位置,limit用来表示能够读的最大位置。
但是读的position和写的position是同一个变量,limit也是。所以写完之后读,和读完之后写都需要手动重置这两个变量。
所以这两个变量的变化是半自动的:
1):在allocate(buffer刚分配好空间或者初始化的时候)的时候,position=0;limit=capacity(分配的容量)。
2): 在写的时候,刚创建一个buffer,当然要先用来写入一些东西。那么所有的写入操作,都会改变position的位置,position就表示了下一个要写入的位置(是内部一个数组的下标),也表示了已经写入的个数。而limit则不会变化。而position写到limit大小的时候就不会再写入了。当然是否到达需要自己调用remain()判断,不然就异常。
3):在读的时候,写过的数据当然要开始读了,但是这个时候,position指向的是下一个要写入的位置,limit指向的是最大容量。我们要读取当然要从0开始读,读到我们最后一个写入的位置。这个时候就需要手动修改position的值,让position=0;我们还要记下我们最后一个写入的位置,那么在positon=0之前,让limit=position,这样,position就是开始读取的位置,limit就是能够读的最大位置。而buffer提供了这样一个方法flip(),源码里就写了这两句:limit=position;position=0;
接着开始读取,每次读取都会让position位置发生改变,直到读取到limit位置。需要自己调用remain()判断,不然报异常。
4):好了,读取过数据我们又需要存储数据了,这就有个问题,如果上次读取没有读取完怎么办?这个烧脑的问题的答案,当然是建议每次都读取完,不要给自己添麻烦。
当然如果真的不能读取完,那么我们需要将剩余的数据移到buffer的position=0的位置,buffer也提供了这么一个方法compact();会将剩余数据移动到buffer起始处,自动重置position和limit,使position等于剩余字节数,limit等于最大容量。
如果是全部读取完,接着我们又要往buffer存数据,这个时候position是上次读取的位置,limit是最大可读取位置,全部读取完成position=limit。那么直接往buffer写,就会出错,因为posiont必须小于limit。而我们也想从0位置开始存储,并且需要最大存储限制limit应该是容量capacity。那我们就要手动修改position和limit的数值。让position=0;而limit=capacity;buffer也提供了这个方法clear();
总结:创建一个buffer------>存储数据------->调用flip()
/\ |
| 循环 |
| \/
调用clear()<------读取数据
当然这是个逻辑清晰的基本操作。掌握了limit,position的含义,理解他们需要手动来改变,你还可以做更多的操作。下载源码,硬着头皮去看,会发现源码注释里面讲的真清晰,图也画的很漂亮。
需要注意的是:tcp框架Mina和Netty中,Mina最终使用了java nio-buffer,所以操作和上述基本一致。Netty使用的不是java nio-buffer,所以不需要以上操作,netty的buffer中读和写的positon和limit是分开的。
https://blog.csdn.net/zhuzi147/article/details/88211129