NIO之ByteBuffer

本文深入探讨了Java NIO中的ByteBuffer,包括它的两种类型:直接缓冲区和非直接缓冲区。详细阐述了ByteBuffer的属性,如capacity、limit、position和mark,并通过实例说明了如何创建、存取数据、调整缓冲区状态。此外,文章还讨论了非直接缓冲区的创建、put和get操作,以及flip、clear、mark和reset方法的用途。最后,对比了直接缓冲区与非直接缓冲区的差异,并强调了ByteBuffer在并发操作中的线程不安全性。
摘要由CSDN通过智能技术生成

关键词:ByteBuffer    NIO

 


ByteBuffer是java.nio包下的类,看见nio就会想到,它与非阻塞IO是有关系的。ByteBuffer有很多兄弟姐妹,比如:CharBufferDoubleBufferFloatBufferIntBuffer等。这些类都有共同的父类Buffer。见名思意,ByteBuffer是操作字节数据的,IntBuffer是操作整形数据的。在ByteBuffer维护了一个byte[] hb数组,在IntBuffer里维护了一个int[] hb数组。


█ 总体认识

类图:

相关概念:

ByteBuffer分两种,Direct和non-direct buffers。Direct buffer有MappedByteBuffer、DirectByteBuffer、DirectByteBufferR。non-direct buffer有HeapByteBuffer和HeapByteBufferR。Direct buffer即操作直接内存,直接内存指内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)。通过调用方法allocateDirect(int)来获取直接内存buffer。non-direct buffer即操作堆内存。通过方法allocate(int)获取。(点击查看直接内存的解释)。HeapByteBufferR和DirectByteBufferR,在拼写上多了个R,这个R是read-only(只读)的意思。

ByteBuffer继承自Buffer,在Buffer中定义了下面四个int类型的属性:

capacity:一个buffer的capacity是指它所包含的元素数量。该值永远不会为负数,也永远不会改变。(给定了初始值之后就不会改变了)。对于non-direct buffers,在内部维护一个字节数组用于存放元素,这里的capacity大小也就是指定了这个数组的大小。

limit:是buffer中第一个不能够被读取或写入的元素的索引值(元素是存放在数组中的,元素的索引值即数组的下标),该值永远不会为负数,并且不能比capacity值大。

position:和limit相对,是buffer中第一个能够被读取或写入的元素的索引值。该值永远不会为负数,并且不能比limit值大。初始化的时候为0,每往buffer存放数据,position的值都会加1。

mark:定义了这样的一个元素索引值,当调用reset方法时,position的值就等于mark值。若没有定义,调用reset方法会报InvalidMarkException。这个值从来不会被定义,但是一旦被定义,该值永远不会为负数,并且不能比position的值大。当定义了mark,如果调整之后的position或limit的值小于了mark值,则mark值会失效(值为-1)。mark未被定义时的值是-1,一旦被定义,值就不能是负数了。

由此可见,上面四个属性的大小关系是:0<=mark<=position<=limit<=capacity。一个新创建的buffer,position初始化为0,mark不会被定义,即值为-1。从limit、position的定义可以看出,最大的数据读取或写入长度是limit减去position。若position=0,limit=5,则此时最大的读取存放数据的长度就是5。数组的下标范围其实是从0到4。可以理解成是一种左闭右开的关系,即包括position的位置,不包括limit的位置。也可以说是读取存放数据的数组下标是从position开始到limit-1的下标位置。记住position和limit的意义和关系,就方便理解ByteBuffer了。

还有一个属性:offset。当前与position与下一次position(position+1)的偏移量。是在position加1之后再进行相加的值,来确定元素的起始位置。默认值为0。可以认为是通过position和offset来确定元素的数组下标的。

若offect=0,添加元素时的情况是这样的:

若offect=2,添加元素时的情况是这样:


█ non-direct buffers

①创建初始化

// 通过方法创建堆内buffer,这里是创建一个capacity为10的buffer。
// buffer在内部维护了一个字节数组final byte[] hb,这里的10也就是初始化了数组的长度。
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    // 创建的是HeapByteBuffer对象,第一个参数是指定capacity的值,第二个参数是指定limit的值。    
    return new HeapByteBuffer(capacity, capacity);
}
HeapByteBuffer(int cap, int lim) {
    // 注意这里的new byte[cap]
    // supper调用了ByteBuffer的构造函数
    super(-1, 0, lim, cap, new byte[cap], 0);
    
}
ByteBuffer(int mark, int pos, int lim, int cap, 
             byte[] hb, int offset)
{
    super(mark, pos, lim, cap);
    // 初始化了一个大小为capacity的字节数组,并赋给
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值