private int mark = -1 mark 是 Buffer 中的一个标志位,用来标志原来的 position 的位置。
当 Buffer 中必要行止理惩罚其他位置的数据的时候,可以使用 mark 先标志一下原来的位置,等处理惩罚完再回到原来的 position 继承处理惩罚
如果调用者想要多此读取同一部分的数据,可以使用 mark 来标志原来的 position,读完之后再设置 position = mark,就可以重复读取了
下面来看下 mark 的用法,我们用 mark 来实现对 Buffer 的一段数据重复读:
public class MarkTest {
public static void main(String[] args) {
IntBuffer buffer = IntBuffer.allocate(10);
buffer.put(1);
buffer.put(2);
buffer.put(3);
buffer.put(4);
// 切换读模式
buffer.flip();
// 做下标记
buffer.mark();
System.out.println(buffer.get()); // 1
System.out.println(buffer.get()); // 2
// 回到标记的位置,就是下标 0 的位置
buffer.reset();
System.out.println(buffer.get()); // 1
System.out.println(buffer.get()); // 2
}
}
复制代码
可以看到,上面再 buffer 切换读模式之后,调用 mark 做了标志,然后再调用 reset 就可以回到标志的位置。这里提前剧透下,所谓的标志就是 position,一开始切换到读模式之后 position = 0,所以 mark = position = 0,调用 reset 之后 position 重新设置为 0,继承从头开始读取。
* Creates a new buffer with the given mark, position, limit, and capacity, after checking invariants.
* @param mark
* @param pos
* @param lim
* @param cap
*/
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
// 1.设置capacity
this.capacity = cap;
// 2.设置limit
limit(lim);
// 3.设置position
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("
+ mark + " > " + pos + ")");
// 4.设置mark
this.mark = mark;
}
}
复制代码
上面构造器的源码就是在设置这几个属性,那么来看下 limit 的逻辑。
/**
* Sets this buffer's limit. If the position is larger than the new limit
* then it is set to the new limit. If the mark is defined and larger than
* the new limit then it is discarded.
* 设置limit
*
* @param newLimit
* The new limit value; must be non-negative
* and no larger than this buffer's capacity
*
* @return This buffer
*
* @throws IllegalArgumentException
* If the preconditions on <tt>newLimit</tt> do not hold
*/
public final Buffer limit(int newLimit) {
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
// 设置limit
limit = newLimit;
// 如果position比新的limit要大,就需要更新position到最新的newLimit
if (position > newLimit) position = newLimit;
// 如果mark比新的limit要大,就重置mark
if (mark > newLimit) mark = -1;
return this;
}
复制代码
设置 limit 的时候,我们之前就知道了 limit 就是用来标志 position 的,如果 position 比新设置的 limit 大,那么更新 position 为最新的 limit。
在写模式下,其实 limit 就是容量长度
在读模式下,limit 就是写模式下的 position
如果 position 比新设置的 limit 大,比如切换写模式之后重新设置 limit 值,这时候就得重新设置 position,别写越界了。
下面如果 mark 比新的 limit 要大,就重置 mark。照旧一样的逻辑,mark 标志的是 position 的位置,如果原来 position 都比 limit 大了,那么就阐明限制变小了,这时候设置 mark = -1。
反之就是 position 和 mark 都比 limit 小,其实也不影响写入和读取,所以不消管。
然后下面就是设置 position 的逻辑。
public final Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw createPositionException(newPosition);
// 如果mark比新的newPosition要大,就重置下
if (mark > newPosition) mark = -1;
position = newPosition;
return this;
}
复制代码
设置 position 的时候,必要判断不能比 limit 大,同时要设置下 mark,如果 mark 比新的 newPosition 要大,就阐明 position 指针往左移动了,这时候 mark 标志的就是无效数据了,所以设置为 -1,看下面的图。