之前看过相关的ByteBuffer的使用,但是问题是那时还年轻,所以现在有点老了,因此,忘记了,所以决心看源代码了解一番----故作此篇文章。

 

查看ByteBuffer的API,看的我是一头雾水,搞不清什么mark、position、limit、flip、reset几个的用法,先看下面的例子:

String str = "helloWorld";
        ByteBuffer buff  = ByteBuffer.wrap(str.getBytes());
        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
        //读取两个字节
        buff.get();
        buff.get();
        System.out.println("position:"+ buff.get(buff.position())+"\t limit:"+buff.limit());
        buff.mark();
        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
        buff.flip();
        System.out.println("position:"+buff.position()+"\t limit:"+buff.limit());
输出结果:
position:0  limit:10
position:2  limit:10
position:2  limit:10
position:0  limit:2

   我们以每位开发人员熟悉的”helloworld“,用ByteBuffer将字符串包装,由于ByteBuffer是一个抽象类,通过wrap包装的对象将实际返回的是一个HeapByteBuffer对象。由此可知HeapByteBuffer是ByteBuffer的子类,同样的ByteBuffer又是Buffer抽象类的子类。以上提到的mark、position、limit、flip、reset都是出自于Buffer这个抽象类。

下面我们来解析几个方法的,当我们调用了wrap方法后Buffer中初始化的结构是:

注释:

m:mark;

p:position;

L:limit;

 

   初始情况下mark是指向第一个元素之前的的即-1,postion为指向第一个元素为0.而Limit是被赋值为byte[]的长度。

因此这就是打印结果的第一行。

m

p

L

-1

0

1

2

3

4

5

6

7

8

9

H

E

L

L

O

W

O

R

L

D

position:2  limit:10结果.

m、p

L

-1

0

1

2

3

4

5

6

7

8

9

H

E

L

L

O

W

O

R

L

D

     读取完毕后我们使用mark,这个时候mark会从-1移动到2和position指向同一个元素,可以看见Limit是不会发生改变的。

m

p

L

-1

0

1

2

3

4

5

6

7

8

9

H

E

L

L

O

W

O

R

L

D

    使用了mark标记的当前的position后,如果们调用flip,这个时候Limit就会指向position的位置,并将mark和position还原为初始值。这样就知道了limit当前的就为2,什么意思呢?就是说当前可以读的字节数是2。

我们可以尝试一下如下代码:

System.out.println((char)buff.get()+""+(char)buff.get());

    貌似这也没什么稀奇的,如果你在代码换成

// System.out.println((char)buff.get()+""+(char)buff.get()
    System.out.println((char)buff.get()+""+(char)buff.get()+""+(char)buff.get());
输出结果:
position:0	 limit:10
Exception in thread "main" java.nio.BufferUnderflowException
	at java.nio.Buffer.nextGetIndex(Buffer.java:474)
	at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:117)
	at com.taobao.moxing.notify.Main.main(Main.java:33)position:2	 limit:10
position:2	 limit:10
position:0	 limit:2

    而至于reset方法,它是将当前的position设置为0,

     rewind是将mark重置为-1,position重置为0;

     clear方法是真正的重置,将mark=-1,position=0,limit=capacity(即当前buffer的容量)