简介
本文主要记录Bytebuffer学习过程中笔记
数据结构
public abstract class ByteBuffer
extends Buffer
implements Comparable<ByteBuffer>
{
// These fields are declared here rather than in Heap-X-Buffer in order to
// reduce the number of virtual method invocations needed to access these
// values, which is especially costly when coding small buffers.
//
final byte[] hb; // Non-null only for heap buffers
final int offset;
boolean isReadOnly; // Valid only for heap buffers
public abstract class Buffer {
/**
* The characteristics of Spliterators that traverse and split elements
* maintained in Buffers.
*/
static final int SPLITERATOR_CHARACTERISTICS =
Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
// Invariants: mark <= position <= limit <= capacity
private int mark = -1; //记录当前position的值。position被改变后,可以通过调用reset() 方法恢复到mark的位置。
private int position = 0; //下一个读写位置的索引(类似PC)。缓冲区的位置不能为负,并且不能大于limit
private int limit; //缓冲区的界限。位于limit 后的数据不可读写。缓冲区的限制不能为负,并且不能大于其容量
private int capacity; //缓冲区的容量。通过构造函数赋予,一旦设置,无法更改
// Used only by direct buffers
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
以上四个属性必须满足以下要求
mark <= position <= limit <= capacity
方法分析
在往Bytebuffer中读写数据时需要开启读写模式。经常需要进行读写切换,其实就是一个数组加上两个指针position和limit的变换。
put()方法
put()方法可以将一个数据放入到缓冲区中。进行该操作后,postition的值会+1,指向下一个可以放入的位置。capacity = limit ,为缓冲区容量的值。
测试一下,跟一下源码
首先判断一下当前position是否大于等于limit,是的话说明buffer数组已满,写不下了,抛出异常。
否则把position++之后,往buffer的position位置写入值。
![在这里插入图片描述](https://img-blog.csdnimg.cn/a559a047148f4df99b69ef50d2c094ff.png
flip()方法
flip()方法会切换对缓冲区的操作模式,由写->读
进行该操作后
写模式->读模式,position = 0 , limit 指向最后一个元素的下一个位置,capacity不变
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
get()方法
get()方法会读取缓冲区中的一个值
进行该操作后,position会+1,如果超过了limit则会抛出异常
注意:get(i)方法不会改变position的值
public byte get() {
return hb[ix(nextGetIndex())];
}
rewind()方法
该方法只能在读模式下使用
rewind()方法后,会恢复position、limit和capacity的值,变为进行get()前的值
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
clean()方法
clean()方法会将缓冲区中的各个属性恢复为最初的状态,通常用在读模式切换至写模式,position = 0, capacity = limit
此时缓冲区的数据依然存在,处于“被遗忘”状态,下次进行写操作时会覆盖这些数据
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
debug下可以看到clean()后,buffer数组内容并没有清空,只是调整了两个指针,下次写的时候直接覆盖而言。
mark() 和 reset()方法
mark()方法会将postion的值保存到mark属性中
reset()方法会将position的值改为mark中保存的值
使用的场景就是如果你想要返回到之前的某一个位置上再进行一次读操作,可以在之前的那个位置进行一次mark(),读到后面的时候 调用reset(),就可以把指针设置成mark()时的值。
compact()方法
compact会把未读完的数据向前压缩,然后切换到写模式数据前移后,原位置的值并未清零,写时会覆盖之前的值。
public ByteBuffer compact() {
//该方法把position指针后的未读的数据都拷贝一份赋值到buffer数组(从下标0开始覆盖)
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
position(remaining());
limit(capacity());
discardMark();
return this;
}