java nio之Buffer

Buffer对象是固定数量的数据的容器,其作用是一个存储器,或者分段运输区,在这里数据可被存储并在之后用于检索
Buffer类家谱:
CharBuffer IntBuffer LongBuffer DoubleBuffer ShortBuffer FloatBuffer ByteBuffer MappedByteBuffer

- 基本属性
容量(Capacity)
缓冲区能够容纳数据元素的最大数量,初始化时被设定,永远不能更改
上界(Limit)
缓冲区第一个不能被读或者写的元素。缓冲区现存元素的计数
位置(position)
下一个要被读或者写的元素的索引,被函数get()和put()更新
标记(Mark)
一个备忘位置,调用函数reset()使得position=mark,函数mark()使得mark=position,注意mark总是小于position,如果position()函数改变position位置小于mark,mark会被标记为-1
这四个属性总是遵循以下关系:
0<=mark<=position<=limit<=capacity

- 创建一个buffer
新缓冲区由分配或者包装操作创建,分配操作创建一个缓冲区对象并分配一个私有空间来存储数据。包装操作创建一个缓冲区对象但是不分配任何空间来存储数据,使用之前提供的数组作为存储空间
分配创建buffer:
CharBuffer charBuffer = CharBuffer.allocate(100);
这段代码隐含地从堆空间分配了一个char新数组作为备份存取来存储100个char
包装创建buffer:
char[] myArray = new char[100];
CharBuffer charBuffer = CharBuffer.wrap(myArray);
使用包装方式可以使用offset和length参数来初始化position与limit
CharBuffer charBuffer = CharBuffer.wrap(myArray,10,20);
position为10,limit为30,注意这个方法只是设置了buffer的初始参数,不代表只能使用长度为20的缓冲区,使用clear()函数,可以重写数组中全部元素
存取
get() get(int index) put() put(int index)
翻转
写满缓冲区,需要读取时需要执行
buffer.limit(buffer.position()).position(0)
即将上限设置为当前位置,且将position设置为0,api中提供函数flip()与这个操作等价
释放
函数hasRemaining()返回当前position是否到达limit位置,remaing()函数返回当前位置到上界还剩余的元素数目。clear()函数将缓冲区重置,注意clear不改变缓冲区任何数据仅仅将上界设置为容量值,并将位置设置为0即:buffer.limit(buffer.capacity()).position(0)
压缩
compact()将未读元素下移,使得第一个未读元素索引为0,该方法使得limit=capacity,position指向最后一个未读元素的下一个位置(注意该位置及以后位置的元素值并不会改变)
标记
mark(); mark=position
reset(); position=mark
比较
equals():
对象类型相同byte永远不可能与非byte相等
两个对象剩余相同数量的元素,即limit-position必须相同
get()函数返回的剩余元素必须相同

compareTo():
不允许不同对象buffer比较,直接比较两个buffer中get()的元素,直到不相等的元素被发现,以第一个不相等的元素的大小比较两个缓冲区大小,如果一个缓冲区在不相等元素发现之前已经被耗尽,较短的较小。注意这个函数比较大小时,position至limit之间未被填充的部分也会参与比较,小于任何有值的元素
批量移动
buffer.get(myArray),等价与buffer.get(myArray,0,myArray.length);
将buffer批量get()的内容放到数组myArray的指定位置,put()也有类似的函数批量添加元素
复制缓冲区
Duplicate()创建一个与原始缓冲区相似的新缓冲区,两个缓冲区共享数据元素,但每个缓冲区拥有各自的位置、上界和标记,对缓冲区元素所做的改变会反映在你一个缓冲区上。如果原始缓冲区为只读或者直接缓冲区,新的缓冲区也将继承这些属性
asReadOnlyBuffer()复制一个只读缓冲区视图,除了不能使用put() isReadOnly()返回为true外与duplicate()完全相同
slice()创建一个从原始缓冲区的当前位置开始的新的缓冲区,并且其容量是原始缓冲区的剩余数量,这个缓冲区与原始缓冲区共享一段数据元素子序列。分隔出来的缓冲区也会继承只读和直接属性
注意复制时position、mark属性初始值与原缓冲区相同

直接缓冲区
直接缓冲区被用于通道与固有I/O例趁交互。使用固有代码告知操作系统直接释放或者填充内存区域,直接字节缓冲区通常是I/O操作最好的选择,通常非直接缓冲不能成为一个本地I/O操作的目标。如果向通道中传递一个非直接ByteBuffer对象用于写入,通道可能会在每次调用中进行以下操作:
1、创建一个临时的直接ByteBuffer
2、将非直接缓冲区的内容复制到临时缓冲
3、使用临时缓冲区执行低层次I/O操作
4、临时缓冲区离开作用域,最终被回收
以上操作可能产生大量临时byteBuffer对象,我们可以选择使用直接缓冲区避免这个现象,但直接缓冲区是通过调用本地操作系统方面的代码分配的,绕过了标准的jvm堆栈,建立和销毁直接缓冲区会明显比具有堆栈的缓冲区更加破费
函数 allocateDirect()可以创建直接缓冲区,isDirect()可以判断是否是直接缓冲区,所有通过包装创建的缓冲总是非直接的

视图缓冲区
I/O操作时只能使用字节数据四处传递,因此对于ByteBuffer可以创建各种其他数据类型的视图缓冲区,asCharBuffer() asShortBuffer() asIntBuffer() asLongBuffer() asFloatBuffer() asDoubleBuffer(),新的缓冲区的容量是字节缓冲区中存在的元素数量除以视图类型中组成一个数据类型的字节数,在切分中任何一个超过上界的元素对于这个视图缓冲区都是不可见的。视图缓冲区的第一个元素从创建它的ByteBuffer对象的位置开始(position位置)。具有能被自然数整除的数据元素个数的视图缓冲区是一种较好的实现

字节顺序
非字节类型的基本类型,除了布尔都是由组合在一起的几个字节组成的,例如int值5870099 对应字节0x037fb4c7 ,每个基本数据类型都是以连续的字节序列的形式存储在内存中的,如果使用大端字节顺序为03 7F B4 C7如果使用小端字节顺序则存储顺序为 C7 B4 7F 03
字节顺序一般由硬件设计决定,intel处理器使用小端字节,JVM运行的硬件平台的固有字节顺序可以使用nativeOrder()查看,ByteBuffer的字符顺序可以随时调用order()函数来改变(这个函数也可以用来查看byteBuffer的字节顺序),在创建视图缓冲区时,如果这个视图的字节顺序和本地机器硬件的字节顺序一直,低等级的语言代码可以直接存取缓冲区中的数据值,而不是通过比特数据的包装和解包装来完成

数据元素视图
getInt() getShort() getLong() getFloat() getDouble() getChar()
调用这些方法时会从选取当前位置开始的若干字节,包装成指定的数据类型返回,注意所有这些方法均可以指定读取位置(对于这种定制位置的读取均不改变当前position),例:getInt(),从当前位置开始的四个字节会被包装成一个int类型的变量返回值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值