抛开其他,先来了解一下
Buffer
。
Buffer
type | buffer |
---|---|
byte |
ByteBuffer |
char |
CharBuffer |
short |
ShortBuffre |
int |
IntBuffre |
float |
FloatBuffer |
double |
DoubleBuffer |
long |
LongBuffer |
boolean |
- |
对于八种基本类型,除了boolean
都有对应的Buffer
。
Buffer
的几个属性
Buffer
的话,说白了就是个单一类型的容器。
capacity
容器的上限,超过就存不下了。
limit
已存储的,或可存储的最后一位。
初始化时,或者clear
初始化操作后,总是挪到最后一位,也就是limit = capacity
。
当翻转flip
后,指向最后一个元素位置。所以limit <= capacity
。
position
我们写入put
和读取get
操作时,读取的就是position
位置的元素。
不过在写入或读取之后,它会自动跳转到下一个位置,也就是+1
。
不过,它的极限也就是limit
了,也就是position <= limit
mark
不算做是很重要的属性,但是又额外功能。
主要目的就是标记一个元素,reset
复位后就可以回到原来的位置了。
所以mark <= position <= limit <= capacity
。
Buffer
的几个行为allocate
:创建capacity
:获取上限值position
:调整position
值mark
:标记mark
,默认-1
limit
:获取limit
put
:放入一个值,position
自动加一get
:读取一个值,position
自动加一clear
:``position=0, limit=capacity`flip
:limit=position, position=0
,状态翻转remaining
:limit -position
,判断是否还有更多元素hasRemaining
:position < limit
,同上基于简单的理解而实现,仅仅基本操作,不涉及更多内容。
public class IntBuffer {
private int capacity;
private int limit;;
private int position;
private int mark;
private int [] arr;
private IntBuffer(int capacity){
this.arr = new int[capacity];
this.capacity = capacity;
this.limit = this.capacity;
this.position = 0;
this.mark = -1;
}
public static IntBuffer allocate(int capacity){
return new IntBuffer(capacity);
}
public int capacity(){
return this.capacity;
}
public IntBuffer position(int position){
this.position = position;
return this;
}
public IntBuffer limit(int limit) {
this.limit = limit;
return this;
}
public IntBuffer mark(){
this.mark = this.position;
return this;
}
public IntBuffer reset(){
this.position = this.mark;
return this;
}
public IntBuffer clear(){
this.position = 0;;
this.limit = this.capacity;
return this;
}
public IntBuffer flip(){
this.limit = position;
this.position = 0;
return this;
}
public IntBuffer put(int value){
if(this.position < this.limit){
this.arr[position++] = value;
}
return this;
}
public int get() throws Exception {
if(this.position < this.limit){
return this.arr[this.position++];
}
throw new Exception("last index");
}
public boolean hasRemaining(){
return position < limit;
}
public int remaining(){
return limit - position;
}
}
简单逻辑实现,为了清晰,更多判断未加上。
public class Main {
public static void main(String[] args) throws Exception {
IntBuffer buffer = IntBuffer.allocate(10);
Random random = new SecureRandom();
while(buffer.hasRemaining()){
buffer.put(random.nextInt(20));
}
buffer.flip();
while(buffer.hasRemaining()){
System.out.println(buffer.get());
}
}
}
ByteBuffer
的归一底层的存储,其实都是字节,也就是说,不论何种类型,底层都可以看做是
ByteBuffer
。当
ByteBuffer
以一种固定的编解码读取字节数据,就成了各种特定的SomethingBuffer
。所以,
ByteBuffer
可以算作是可以存取任意类型基本数据类型的归一化容器。
public class Main {
public static void main(String[] args) throws Exception {
ByteBuffer buffer = ByteBuffer.allocate(256);
int lastIndex = buffer.position();
int nowIndex = buffer.position();
buffer.putInt(1);
nowIndex = buffer.position();
show("int : " + (nowIndex - lastIndex));
lastIndex = nowIndex;
buffer.putDouble(2.0d);
nowIndex = buffer.position();
show("double : " + (nowIndex - lastIndex));
lastIndex = nowIndex;
buffer.putFloat(3f);
nowIndex = buffer.position();
show("float : " + (nowIndex - lastIndex));
lastIndex = nowIndex;
buffer.putLong(4l);
nowIndex = buffer.position();
show("long : " + (nowIndex - lastIndex));
lastIndex = nowIndex;
buffer.putShort((short)5);
nowIndex = buffer.position();
show("short : " + (nowIndex - lastIndex));
lastIndex = nowIndex;
buffer.put((byte)6);
nowIndex = buffer.position();
show("byte : " + (nowIndex - lastIndex));
lastIndex = nowIndex;
buffer.putChar('a');
nowIndex = buffer.position();
show("char : " + (nowIndex - lastIndex));
buffer.flip();
show(buffer.getInt());
show(buffer.getDouble());
show(buffer.getFloat());
show(buffer.getLong());
show(buffer.getShort());
show(buffer.get());
show(buffer.getChar());
}
public static void show(Object obj){
System.out.println(obj);
}
}
可以看到我们利用ByteBuffer
不仅可以针对进行写入,还能针对进行读取。
但是类型一定要对应,否则会解码失败,从而报错。
而且,顺便复习一下基础占据空间大小。
byte
:1byte, 8bit
char
:2byte,16bit
short
:2byte,16bit
int
:4byte,32bit
float
:4byte,32bit
double
:8byte,64bit
long
:8byte,64bit
slice
public class Main {
public static void main(String[] args) throws Exception {
IntBuffer buffer = IntBuffer.allocate(5);
for(int i = 0;i < buffer.capacity(); i++ ){
buffer.put(i);
}
buffer.position(1);
buffer.limit(4);
IntBuffer sliceBuffer = buffer.slice();
while(sliceBuffer.hasRemaining()){
show("slice : " + sliceBuffer.get());
}
show("====================");
buffer.clear();
while(buffer.hasRemaining()){
show("source : " + buffer.get());
}
}
public static void show(Object obj){
System.out.println(obj);
}
}
slice
返回的是buffer
[ p o s i t i o n , l i m i t ) [position,limit) [position,limit)区间的元素,同时,两者共用的是同一块空间,同一个存储结构。
public class Main {
public static void main(String[] args) throws Exception {
IntBuffer buffer = IntBuffer.allocate(5);
for(int i = 0;i < buffer.capacity(); i++ ){
buffer.put(i);
}
buffer.position(1);
buffer.limit(4);
IntBuffer sliceBuffer = buffer.slice();
while(sliceBuffer.hasRemaining()){
show("slice : " + sliceBuffer.get());
}
show("====================");
buffer.clear();
while(buffer.hasRemaining()){
show("source : " + buffer.get());
}
}
public static void show(Object obj){
System.out.println(obj);
}
}
如果还需要警惕什么,就是clear
只是:position=0,limit-capacity
,并没有真正的删除数据。
对于linux
中的一些数据删除,也是如此,只是取消了文件标记,但是数据仍然存在。
asReadOnlyBuffer
public class Main {
public static void main(String[] args) throws Exception {
IntBuffer buffer = IntBuffer.allocate(2);
buffer.put(1);
buffer.put(2);
IntBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
buffer.put(1,9);
// readOnlyBuffer.clear();
while(readOnlyBuffer.hasRemaining()){
show("read:" + readOnlyBuffer.get());
}
}
public static void show(Object obj){
System.out.println(obj);
}
}
运行是没有结果的,但是把注释打开
readOnleBuffer.clear();
readOnly
就不用说了,为什么不clear
就没有结果。
因为返回的readOnlyBuffer
和slice
不太一样,它会复制此时buffer
的position
和其他属性。
例子中已经读取到结尾,所以就不会出现结果了。
除了position
状态保留的差异,也可以看到,也共享同一块内存空间,会受到原有buffer
写操作的影响。