NIO-ByteBuffer API使用详解(堆外内存)

bytebuffer其实就是缓存区,缓冲区就是在内存中预留指定大小的存储空间对I/O数据作临时存储,这部分内存空间即为缓冲区。使用缓冲区可以减少动态分配和回数内存的次数。在java NIO中,缓冲区的作用也是用来临时存储数据。缓冲区可以看作通道(channel)与客户端(或服务器)的中转站,写入数据到channel或者从channel中读取数据,这样利于数据的高效读写。

一、 Fields

所有缓冲区都有四个属性:capacity、limit、position、mark,并遵循:mark <= position <= limit <= capacity,以下是对四个属性的解释

属性 描述
Capacity 容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变
Limit 表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作。且极限是可以修改的
Position 位置,下一个要被读或写的元素的索引,每次读写缓冲区数据时都会改变改值,为下次读写作准备
Mark 标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置

二、Methods

java.nio.Buffer类是一个抽象类,不能被实例化。Buffer类的直接子类也不能被实例化,例如ByteBuffer。但是ByteBuffer类提供了4个静态工厂方法来获得ByteBuffer的实例:

方法 描述
allocate(int capacity) 从堆空间中分配一个容量大小为capacity的byte数组作为缓冲区的byte数据存储器
allocateDirect(int capacity) 分配直接缓冲区,在缓冲区较大并长期存在,或者需要经常重用时,才使用这种缓冲区
wrap(byte[] array) 这个缓冲区的数据会存放在byte数组中,bytes数组或buff缓冲区任何一方中数据的改动都会影响另一方。其实ByteBuffer底层本来就有一个bytes数组负责来保存buffer缓冲区中的数据,通过allocate方法系统会帮你构造一个byte数组
wrap(byte[] array,int offset, int length) 在上一个方法的基础上可以指定偏移量和长度,这个offset也就是包装后byteBuffer的position,而length呢就是limit-position的大小,从而我们可以得到limit的位置为length+position(offset)

三、ByteBuffer读写方法

方法 描述
limit(), limit(10)等 读取和设置这4个属性的方法的命名和jQuery中的val(),val(10)类似,一个负责get,一个负责set
reset() 把position设置成mark的值,相当于之前做过一个标记,现在要退回到之前标记的地方
clear() position = 0;limit = capacity;mark = -1; 有点初始化的味道,但是并不影响底层byte数组的内容
flip() limit = position;position = 0;mark = -1; 翻转,也就是让flip之后的position到作准备limit这块区域变成之前的0到position这块,翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态
get() 相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
getLong(),getInt()... 相对带java类型得读取
getLong(int index),getInt(int index)... 绝对带java类型得读取
slice() 创建共享缓冲区,返回得新的bytebuffer所有下标重新开始,但是和原bytebuffer共享缓冲区,其容量和限制将为该缓冲区中剩余的浮点数

demo案例

public class ByteBufferTest {
    public static void main(String[] args) {
        int capacity = 1024;
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect( capacity );
        byteBuffer.putChar( 'A' );
        byteBuffer.putLong( 333l );
        byteBuffer.putChar( 'B' );
        int pre = byteBuffer.position(); //获取当前写入指针得下标
        byteBuffer.flip(); //切换读取模式,position初始为0,limit初始为可读取数据得最大下标
        System.out.println( byteBuffer.getChar() );
        System.out.println( byteBuffer.getLong() );
        System.out.println( byteBuffer.getChar() );
        byteBuffer.position( byteBuffer.limit() ); //重新初始化写指针下标
        byteBuffer.limit( capacity ); //重新初始化可写入得最大下标
        byteBuffer.putChar( 'C' );
        System.out.println( byteBuffer.getChar( pre ) );
    }
}

猜你喜欢

转载自blog.csdn.net/wmq880204/article/details/115188811