在解释以上方法之前我们需要了解ByteBuffer的几个参数:
// Invariants: mark <= position <= limit <= capacity private int mark = -1;//标记位置,reset时需要 private int position = 0;//当前读取 private int limit;//读取的最大位置 private int capacity;//buffer的容量
下面通过一个最简单的代码来解释,各个过程中上面参数的变化:
//初始化一个长度为48的buffer ByteBuffer buffer = ByteBuffer.allocate(48);
此时 postion:0,limit48,mark:-1,capacity:48。下面的过程主要是postion、limit、mark会变化,capacity是容量不会变化。
//将数据写入buffer buffer.put("123456".getBytes());
写入后ByteBuffer的参数变化如下图:
此时只有postion发生了变化,变成了6,因为我们写了6个字符。我们写入的数据就存储在0-5空间上
flip():接下来我们需要把写入的数据读取出来,这也是buffer的使用场景,那么我们需要调用flip()进行位置翻转
buffer.flip();
执行flip()之后参数变化如下图:
通过上图我们发现 position和limit发生了变化,postion变为:0,limit变为:6(这是flip()翻转之前的postion值)。那么此时我们就可以读取buffer中的数据了
while(buffer.hasRemaining()){ System.out.println((char) buffer.get()); }
下面是buffer.hasRemaining()的代码
通过下面 hasRemaining()的源码我们可以看出,我们只能get()出0-5的位置上的数据,调用while()循环我们会依次打印出1、2、3、4、5、6
public final boolean hasRemaining() { return position < limit; }
接下来我们说下mark()和reset()如何配合使用。
举例一个使用场景我们能更好的理解,假设在读取读取4、5的时候我们需要做一些事务计算,比如g(f(4),f(5)),只要计算错误我们就需要重新读取计算,那么这时候我们就会用到mark()和reset()。
先贴出代码:
while(buffer.hasRemaining()){ char c=(char)buffer.get(); System.out.println(c); if(buffer.position()==3){ buffer.mark(); } if(buffer.position()==4){ a=f(c); } if(buffer.position()==5){ b=f(c); try { System.out.println(g(a,b)); throw new Exception("主动抛出"); } catch (Exception e) { buffer.reset(); } } }
在postion=3时,执行mark()后,mark=3;抛出异常,catch里执行reset()后,postion=mark=3,重新读取4、5。dubug的视图就不再贴出来了。
通过上面论述,相信大家对ByteBuffer的重要参数已经有系统的了解,接下来rewind()和clear()就不难理解了。
以下是这两个方法的源码
rewind:重置mark并将potion设置到起始位置0
clear:重置ByteBuffer的重要参数
public final Buffer rewind() { position = 0; mark = -1; return this; } public final Buffer clear() { position = 0; limit = capacity; mark = -1; return this; }