ByteBuffer类位于java.nio包下,所谓nio:代表new io,另一种解释:N代表Non-blocking IO,非阻塞的IO
Buffer是一个抽象的基类
派生类:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
Buffer的几个基本属性
基础属性,使用ByteBuffer是以字节Byte为基础的,操作对象是字节
capacity--Buffer的容量,读取数据的限制和读取数据的位置,capacity 是分配好的一个内存块大小,分配好后大小不可变
limit--在读的模式下,表示缓存内数据的多少,limit<=capacity; 在写的模式下,表示最多能存入多少数据,此时limit=capacity;简单说:在Buffer上进行的读写操作都不能越过这个下标。
position--表示读写的位置,下标从0开始
Buffer的几个方法
clear()--position置为0,limit转为capacity大小,标记mark也会被清除
flip()--limit被置为当前position的大小,也就是说后续的读操作可能会被限制,这是与clear()有区别的地方;然后position被置为0
rewind()--position置为0,标记被取消
使用举例
基本用法
ByteBuffer byteBuffer = ByteBuffer.allocate(10);//分配10个字节大小的缓存
byteBuffer.putInt(5);//int占用4个字节
byteBuffer.put((byte) 1);//1个字节
byteBuffer.put((byte) 0);//1个字节
byteBuffer.put("abc".getBytes());//2个字节
System.out.printf("position: %d, limit: %d, capacity: %d\n", buf.position(), buf.limit(), buf.capacity());
打印结果:
position: 9, limit: 10, capacity: 10
分析:byteBuffer刚开始分配了10个字节的缓存,放入一个Int值5,占用4个字节,两个byte数又占两个,adb占用三个字节,总共占用了9个字节。从打印结果中看到,position为9表示已经存储了9个字节即下标0-8,limit表示在写模式下最多存储10个字节,capacity为10表示缓存容量为10。
java.nio.BufferOverflowException
因为ByteBuffer的大小不可变的,所以如果存储的长度超过capacity,那么就会抛出java.nio.BufferOverflowException异常,表示缓冲区上溢出,写入的位置超出了内存长度。
flip()和clear()
flip方法的作用是先将limit属性设置为当前的position的值,再将position转为0,并清除标记。
clear方法的不同之处是limit=capacity。
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
byteBuffer.putInt(5);//int占用4个字节
byteBuffer.put((byte) 1);
byteBuffer.put((byte) 0);
byteBuffer.put("abcd".getBytes());
printByteBuffer(byteBuffer);
// 读取消息头,因为写完后position已经到10了,所以需要先反转为0,再从头读取
byteBuffer.flip();//将position置0
//需要按顺序读取,position自增
System.out.printf("读取int值: %d\n", byteBuffer.getInt());//读int
System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
byte[] str = new byte[4];
byteBuffer.get(str, 0, 4);//连续读4个字节,并保存到str中,注意第二个参数是相对于position的偏移量
System.out.println("读取字符串=" + new String(str));
打印结果如下:
position: 10, limit: 10, capacity: 10
读取int值: 5
读取byte值: 1
读取byte值: 0
读取字符串=abcd
java.nio.BufferUnderflowException
试一下flip()的使用。上面介绍中提到,flip()的作用是先将limit属性设置为当前的position的值,再将position转为0。也就是说如果当前的position是小于实际保存的字节长度的,那么下次就最多读取到这个position的位置,如果超出则会抛出异常。
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
byteBuffer.putInt(5);//int占用4个字节
byteBuffer.put((byte) 1);
byteBuffer.put((byte) 0);
byteBuffer.put("abcd".getBytes());
byteBuffer.clear();
//先读取一个int,再flip()
System.out.printf("读取int值: %d\n", byteBuffer.getInt());//读int
byteBuffer.flip();
System.out.printf("position: %d, limit: %d, capacity: %d\n", byteBuffer.position(), byteBuffer.limit(), byteBuffer.capacity());
//需要按顺序读取,position自增
System.out.printf("读取int值: %d\n", byteBuffer.getInt());//读int
System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
System.out.printf("读取byte值: %d\n", byteBuffer.get());//读byte
打印结果:
读取int值: 5
position: 0, limit: 4, capacity: 10
读取int值: 5
java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:500)
at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:135)
at com.heima.ajax.JacksonTest.testByteBuffer(JacksonTest.java:83)
此时报出了内存下溢出的异常,说明读取的位置超出了限制。
参考