ByteBuffer是一个抽象类,继承于Buffer。
ByteBuffer有两个实现类:
HeapByteBuffer:对应,ByteBuffer的alloccate方法。
DirectByteBuffer:对应,ByteBuffer的allocateDirect方法。
先分析HeapByteBuffer。
HeapByteBuffer是在在java堆的分配内存,就像普通的ArrayList或HashMap一样。
其父类Buffer有几个重要的成员变量
// 标记位,reset后position会跳到这个位置,进行重复读
private int mark = -1;
// 实际读或写的位置
private int position = 0;
// 有效数据的位置,读的时候,limit是有效数据,写的时候,limit是容量
private int limit;
// 容量
private int capacity;
ByteBuffer的变量
// 真正存储数据的数据
final byte[] hb;
// 偏移量,byteBuffer可以控制从哪一个位置开始存储数据
final int offset;
ByteBuffer.allocate方法
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
HeapByteBuffer(int cap, int lim) { // package-private
// 初始化:mark = -1, position=0,limit=capacity,offset偏移量为0
super(-1, 0, lim, cap, new byte[cap], 0);
/*
hb = new byte[cap];
offset = 0;
*/
}
ByteBuffer(int mark, int pos, int lim, int cap, // package-private
byte[] hb, int offset)
{
super(mark, pos, lim, cap);
this.hb = hb;
this.offset = offset;
}
put方法:写入数据
public ByteBuffer put(byte[] src, int offset, int length) {
// 检查是否越界
checkBounds(offset, length, src.length);
// 可用位置是否足够
if (length > remaining())
throw new BufferOverflowException();
// 复制byte数组进hb
System.arraycopy(src, offset, hb, ix(position()), length);
// position为put数据后的位置
position(position() + length);
return this;
}
public final int remaining() {
return limit - position;
}
flip:把写入数据的模式切换为读取数据
public final Buffer flip() {
// position为已有数据的长度,limit指向它,或者说有效数据的长度
limit = position;
// 下一个读取数据的位置,从0开始
position = 0;
mark = -1;
return this;
}
get:读取数据
public ByteBuffer get(byte[] dst, int offset, int length) {
checkBounds(offset, length, dst.length);
if (length > remaining())
throw new BufferUnderflowException();
// 复制hb的数据到传入擦书dst中,ix方法是加上偏移量,如果有偏移量的话,数据存储的起始位置就是position + offset
System.arraycopy(hb, ix(position()), dst, offset, length);
position(position() + length);
return this;
}
// 加上偏移量
protected int ix(int i) {
return i + offset;
}
mark:标记重读的位置
public final Buffer mark() {
mark = position;
return this;
}
reset:重mark标记的地方重读
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
compact:压缩数据,把已读数据清除掉。position指向有效数据的位置,也就是从读模式切换为写模式,可以进行put了
public ByteBuffer compact() {
// 移动数组位置,把已读数据清除掉
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
// 重置position位置为有效数据的长度
position(remaining());
// limit为capacity的大小
limit(capacity());
// 丢弃mark,mark = -1
discardMark();
return this;
}
clear:重置为新的Buffer,重新进行写数据
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
slice:切一个子buffer,切掉已读数据部分,hb还是原来的hb,只是偏移量移过已经读过的数据
public ByteBuffer slice() {
return new HeapByteBuffer(hb,
-1,
0,
this.remaining(),
this.remaining(),
this.position() + offset);
}
duplicate : 复制一份一模一样的buffer
public ByteBuffer duplicate() {
return new HeapByteBuffer(hb,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
offset);
asCharBuffer:bytebuffer提供了转成其他类型buffer的方法,并非真正的转,而是保证了byte数组的CharBuffer,直到get或put操作的时候才会将byte转成对应的类型
public CharBuffer asCharBuffer() {
int size = this.remaining() >> 1;
int off = offset + position();
return (bigEndian
? (CharBuffer)(new ByteBufferAsCharBufferB(this,
-1,
0,
size,
size,
off))
: (CharBuffer)(new ByteBufferAsCharBufferL(this,
-1,
0,
size,
size,
off)));
}
// 虽然是charBuffer,但是实际维护的数组还是byte数组
ByteBufferAsCharBufferB(ByteBuffer bb,
int mark, int pos, int lim, int cap,
int off)
{
super(mark, pos, lim, cap);
this.bb = bb;
offset = off;
}
// 直到操作数据的才将byte转成对应的类型
public char get() {
return Bits.getCharB(bb, ix(nextGetIndex()));
}
网友评论