Java Nio Buffer

Buffer是特定基本类型元素的线性有限序列,它以及它的子类定义了一系列API用于处理数据缓存。


伦理片 http://www.gxuy.com/
一、属性
Buffer有四个基本属性:
1、capacity:  容量,buffer能够容纳的最大元素数目,在Buffer创建时设定并不能更改
2、limit: buffer中有效位置数目
3、position: 下一个读或者写的位置
4、mark:  用于记忆的标志位,配合reset()使用,初始值未设定,调用mark后将当前position设为值

不变式 
标记、位置、限制和容量值遵守以下不变式: 
0 <= 标记 <= 位置 <= 限制 <= 容量 

二、API   
public final int capacity( ) 返回此缓冲区的容量。 
public final int position() 返回此缓冲区的位置。 
public final Buffer position(int newPosition) 设置此缓冲区的位置。如果mark已定义且大于新的位置,则丢弃该标记。 
public final int limit( ) 返回此缓冲区的限制。 
public final Buffer limit (int newLimit) 设置此缓冲区的限制。
public final Buffer mark( ) 在此缓冲区的位置设置标记。 
public final Buffer reset( ) 将此缓冲区的位置重置为以前mark的位置。
public final Buffer clear( ) 清除此缓冲区。将position设置为 0,将limit设置为容量,并丢弃mark。  
public final Buffer flip( ) 为读做好准备。它将limit设置为当前位置,然后将position设置为 0。如果已定义了标记,则丢弃该标记。 
public final Buffer rewind( ) 一般flip()只能被执行一次,想第二次执行flip(),请使用rewind()。它使limit保持不变,将position设置为 0 ,并丢弃mark。
public final int remaining( ) 返回当前位置与限制之间的元素数。 
public final boolean hasRemaining( ) 告知在当前位置和限制之间是否有元素。 
public abstract boolean isReadOnly( ) 告知此缓冲区是否为只读缓冲区。 



三、操作(以ByteBuffer为例)

1、访问:
get(),从当前position位置读取
get(index),从index位置读取,不改变当前position,下面要说到的put也一样。

2、填充:
put(byte),在当前position位置填充
put(index,byte),按照绝对位置填充不改变当前position属性

3、flipping,试想,我们将填充完毕的buffer传递给socket输出,那么socket读取是依据position属性确定,就会从结尾后一位开始读,这样肯定是不正确的,如果要正确的读取我们先要:
buffer.limit(buffer.position( )).position(0);
将limit设为position, 将position设为0,这个操作就叫flipping,API直接提供了这个操作:  buffer.flip( );

特别注意,flip()方法会改变limit属性,将limit属性从capacity设置为当前position。
rewind()方法与flip()类似,但是仅将position设为0,而不改变limit,通常用于重新读取已经被flip的buffer。
flip()另一个注意点是,两次调用buffer的flip方法,将使得position和limit属性都为0。

4、迭代取元素:

Java代码   收藏代码
  1. for (int i = 0; buffer.hasRemaining( ), i++) {  
  2. myByteArray [i] = buffer.get( );  
  3. }  
  4.   
  5. int count = buffer.remaining( );  
  6. for (int i = 0; i < count, i++) {  
  7. myByteArray [i] = buffer.get( );  
  8. }  
 


ByteBuffer不是线程安全的,前一种方式适合并发访问,后一种方式效率更高。这两种方式都是一个一个取,效率都比批量取低。


5.clear()方法,将buffer重设为空状态,也就是设置limit=capacity,position=0,以便重复利用。

6.compact()方法,用于压缩buffer,这个方法在多次重复调用时是比较低效。

7.mark(),初始是未定义的,这适合如果调用reset将抛出InvalidMarkException。调用makr()后,将当前position设为mark以便reset时返回。注意,rewind( ), clear( ), and flip( )方法都将丢弃已经创建的mark。调用limit(index),positioon(index),如果index的值小于当前mark,mark也将被丢弃。

8.比较,可以通过equals()和compateTo()方法来比较两个buffer,前一个返回boolean,后一个返回0,-1,1。两个buffer equal的条件是:
1)类型相同
2)剩余元素的数目相等
3)剩余元素也一一相等

9、批量移动数据,为了更有效地进行数据传送,批量的数据存取肯定是不能少的,Buffer及其子类都有提供类似的方法,比如CharBuffer:

Java代码   收藏代码
  1. public CharBuffer get (char [] dst)  
  2. public CharBuffer get (char [] dst, int offset, int length)  
  3. public final CharBuffer put (char[] src)  
  4. public CharBuffer put (char [] src, int offset, int length)  
  5. public CharBuffer put (CharBuffer src)  
  6. public final CharBuffer put (String src)  
  7. public CharBuffer put (String src, int start, int end)  
 



四、创建Buffer
    Buffer以及其子类都无法直接new,而必须把通过他们提供的工厂方法来创建。通常有两种方式:
1、allocate,例如
CharBuffer charBuffer = CharBuffer.allocate (100);
将在堆上分配一个可以存储100个字符的数组作为backing store。

2、wrap,包装一个已有的数组:
char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
注意,这样的方式创建的Buffer,将不会在堆上创建新的数组,而是直接利用myArray做backing store,这意味着任何对myArray或者buffer的修改都将影响到buffer或者myArray。可以通过public final boolean hasArray( )方法来判断是否拥有一个数组,通过array()方法取得这个数组。

五、复制Buffer
   其实这个复制也是“浅拷贝”,通过duplicate()方法将返回一个新创建的buffer,这个新buffer与原来的Buffer共享数据,一样的capacity,但是有自己的position、limit和mark属性。通过asReadOnlyBuffer()方法复制的buffer与duplicate()类似,但是是只读的,不能调用put。比较特别的是slice()方法,故名思议,类似切割一个Buffer出来,与duplicate类似,但是它将从原来Buffer的当前position开始,并且capacity等于原来Buffer的剩余元素数目,也就是(limit-position)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值