Buffer就是一个数据存储器。数据可以存储在其中并在之后用于检索。
在Buffer的源码中可以看到:
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
这四个就是缓冲区的重要属性。
容量(Capacity):缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。
上界(Limit):缓冲区的第一个不能被读或写的元素。或者说,limit后既不可读也不可写。
位置(Position):下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。
标记(Mark):一个备忘位置。调用 mark( )来设定 mark = postion。调用 reset( )设定 position =mark。标记在设定前是未定义的(undefined)。
Buffer类的api方法:

除了boolean其他基本类型都有相应的buffer。常用的为CharBuffer、ByteBuffer。下面是一个简化的类图。

下面我们就来实际操作buffer,以CharBuffer为例。
1.创建一个CharBuffer
CharBuffer charBuffer = CharBuffer.allocate(10);
System.out.println("容量capacity="+charBuffer.capacity()+" 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:容量capacity=10 界限limit=10 位置position=0,关系如下如图

2.向上面的buffer添加四个元素。
charBuffer.put("q");
charBuffer.put("w");
charBuffer.put("e");
charBuffer.put("r");
//加入四个元素 输出:界限limit=10 位置position=4
System.out.println("加入四个元素 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:加入四个元素 界限limit=10 位置position=4,关系如下图

3.调用flip()方法,Buffer从写模式切换到读模式,将limit设置为position,position设为0。
charBuffer.flip();
//输出:界限limit=4 位置position=0
System.out.println("flip()后:界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:flip()后 :界限limit=4 位置position=0,关系如下图

4.此时buffer为可读,我们从中读取数据。
//取出第一个元素
System.out.println("相对取出一个元素get():"+charBuffer.get());
//界限limit=4 位置position=1
System.out.println("相对取出一个元素get()后: 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:相对取出一个元素get()后: 界限limit=4 位置position=1,关系如下图。

5.调用clear()让buffer回到写模式,clear()将limit变为capacity,position=0,上面添加的数据依然存在buffer中。
//clear()将limit变为capacity,position=0,数据依然存在
charBuffer.clear();
//界限limit=10 位置position=0
System.out.println("clear()后:界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:clear()后:界限limit=10 位置position=0,关系如下图,和初始时相似,但现在buffer里有数据。

6.根据索引绝对访问get(x),取值不会影响position
//get(3)根据索引取值不会影响position
System.out.println("根据索引绝对访问get(1)="+charBuffer.get(3));
System.out.println("根据索引绝对访问get(1)后: 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
输出:根据索引绝对访问get(1)=r;根据索引绝对访问get(1)后: 界限limit=10 位置position=0
7.buffer的释放。释放有两种方式:
a.)
CharBuffer buffer1 = CharBuffer.allocate(8);
buffer1.put("a");
buffer1.put("b");
buffer1.put("c");
buffer1.flip();
//释放1,布尔函数 hasRemaining()会在释放缓冲区时判断是否已经达到缓冲区的上界
char[] receive1 = new char[32];
for(int i = 0;buffer1.hasRemaining();i++){
receive1[i] =buffer1.get();
System.out.println("释放1 hasRemaining:receive["+i+"]="+receive1[i]);
}
b.)
CharBuffer buffer2 = CharBuffer.allocate(8);
buffer2.put("1");
buffer2.put("2");
buffer2.put("3");
buffer2.flip();
//释放2,remaining()函数:从当前位置到上界还剩余的元素数目
int count = buffer2.remaining();
char[] receive2 = new char[32];
for (int i=0;i<count;i++){
receive2[i] =buffer2.get();
System.out.println("释放2 remaining:receive["+i+"]="+receive2[i]);
}
8.批量移动,上面说的方式移动数据效率不高,NIO的buffer还提供了更加高效的方式。
package com.nio.java;
import java.nio.CharBuffer;
/**
* 批量移动数据
* @author monkjavaer
* @date 2018/10/16 15:29
*/
public class BufferTest2 {
public static void main(String[] args) {
CharBuffer charBuffer = CharBuffer.allocate(10);
System.out.println("容量capacity="+charBuffer.capacity()+" 界限limit="+charBuffer.limit()+" 位置position="+charBuffer.position());
charBuffer.put("q");
charBuffer.put("w");
charBuffer.put("e");
charBuffer.put("r");
charBuffer.put("t");
charBuffer.flip();
////buffer.get(smallArray);等价于:buffer.get(smallArray,0,smallArray.length);
//如果数组比较小不能装下待处理的数据,就需要指定长度,否则buffer.get(smallArray)会抛出java.nio.BufferUnderflowException
char [] smallArray = new char [2];
while (charBuffer.hasRemaining( )) {
int length = Math.min (charBuffer.remaining( ), smallArray.length);
System.out.println("length="+length);
charBuffer.get (smallArray, 0, length);
processData(smallArray,length);
}
}
/**
* 处理数据
* @param smallArray
* @param length 数组中有多少待处理数据
*/
public static void processData(char [] smallArray,int length){
System.out.println("===processData====");
for (int j =0 ;j<length;j++) {
System.out.println("smallArray["+j+"]="+smallArray[j]);
}
}
}