码迷,mamicode.com
首页 > 编程语言 > 详细

Java NIO 缓冲区 Buffer

时间:2021-01-05 11:42:03      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:int   XML   mes   e30   超过   city   核心   容器   固定   

缓冲区 Buffer 是 Java NIO 中一个核心概念,它是一个线性结构,容量有限,存放原始类型数据(boolean 除外)的容器。

Buffer 中可以存放的数据类型

java.nio.Buffer 是一个接口,有 7 个重要的子类,对应着 7 种(除 boolean 外)原始数据类型:IntBuffer, CharBuffer, FloatBuffer, DoubleBuffer, ShortBuffer, LongBuffer, ByteBuffer。

在使用 Buffer 的时候应该根据要存放的数据类型选择对应的子类型。

创建一个 Buffer

上面所列举的 7 个类是抽象类,不能直接使用 new 关键字来实例化,而应该调用 allocate(int capacity) 方法来实例化一个 Buffer。

CharBuffer buf = CharBuffer.allocate(10);

每个 Buffer 都有其固定的容量,上面这句代码表示创建一个容量为 10 的 CharBuffer,最多可以往 Buffer 中存放 10 个 char 字符。Buffer 中有 3 个重要的属性 capacity, limit, position:

capacity 是一个不可改变的非负整数,它在创建 Buffer 的时候设置。如上面创建的 buf 的 capacity 就是 10。

limit 也是一个非负整数,其值不能超过 capacity。它指向 Buffer 中第 1 个不能够被读或者写的元素。

position 表示 Buffer 中下一个被读取或者写入的单元。

下图为一个 CharBuffer 刚创建时的结构。它的内部存储结构是一个 char[] 数组,capacity 和 limit 指向 10 的位置,position 指向位置 0 。同理,一个 IntBuffer 内部的存储结构为一个 int[] 数组。

7856923014capacity / limitpositionallocate(10)可写

Buffer 的读和写

一个 Buffer 可以处于读模式或者写模式,两种模式可以发生切换。一个刚创建的 Buffer 处于写模式,此时可以往里面写入数据。

put(char c) 写入数据

put(char c) 方法可以往 Buffer 中写入数据。CharBuffer 使用了建造者设计模式,大部分方法都返回了当前对象,可以使用链式调用往 Buffer 中写入数据。

buf.put(‘A‘).put(‘B‘).put(‘C‘).put(‘D‘).put(‘E‘).put(‘F‘).put(‘G‘);

每写入一个 char 数据,position 就移动 1 位。

7856923014capacity / limitposition可写put(‘A‘) ... put(‘G‘)‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacity / limitposition可写

flip() 将写模式切换到读模式

flip() 能够将 Buffer 从写入模式切换成读取模式,它的原理很简单,就是将 limit 移动到了 position 所指位置,将 position 移到了 0 位置。

buf.flip();

buf 内部结构的变化如下图所示。

‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacity / limitposition可写‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacityposition可读limitflip()

get() 读取数据

get() 方法能够读取 Buffer 中的数据,它将 position 所指的元素返回,然后 position 移动 1 个位置,指向下一个应该返回的元素。get() 因为要返回元素,所以它不支持链式调用。

System.out.println(buf.get()); // 输出:A
System.out.println(buf.get()); // 输出:B
System.out.println(buf.get()); // 输出:C

‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacityposition可读limit‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacityposition可读limitget(),get(), get()

mark() / reset() / rewind()

mark() 将记录当前 positon 的位置,reset() 方法需要配合 mark() 使用。调用 mark() 方法的时候,position 将赋值给 mark 属性;可以继续读取,position 往前移动;调用 reset() 之后,position 会重新回退到 mark 位置。

buf.mark();
System.out.println(buf.get()); // 输出:D
buf.reset();

‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacityposition可读limit‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014capacitymark可读limitmark() get()position‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014mark/position可读limitcapacityreset()

mark() 配合 reset() 允许重新读取部分元素,rewind() 允许重新读取全部元素。rewind() 方法直接让 position 指向 0 位置,然后将 mark 清除。

compact()

想象这样一个场景:某个 Buffer 中存储了一条半消息,剩下半条消息的数据还没有全部传输过来;此时需要让 Buffer 切换到读取模式,读取第 1 条消息,让后让剩下的半条消息的数据留在 Buffer 中。compact() 可以很好地处理这样地场景。

compact() 可以将一个未读取完的 Buffer 切换到写模式。它的具体做法是将 [position, limit) 范围内的数据复制到 [0, limit-position),然后 position = limit - position, limit = capacity。此时又可以往 Buffer 中写数据而不会影响未读取的数据了。

buf.compact();
System.out.println(Arrays.toString(buf.array())); // 输出:[D, E, F, G, E, F, G, , , ]

需要注意的是,compact() 仅仅是复制了数据,而并没有将数组中的其它元素设置为零值,如下图所示。

‘F‘‘G‘‘C‘‘D‘‘A‘‘B‘‘E‘7856923014position可读limit‘F‘‘G‘‘F‘‘G‘‘D‘‘E‘‘E‘7856923014position可写capacitycapacity / limitcompact()

clear()

clear() 方法可以认为是将 Buffer 重置了,将 Buffer 切换到了写模式。实际上它只是将 position, limit 的值重置了,position=0, limit = capacity。

小结

Buffer 是一个缓冲数据的容器,其内部结构是一个固定长度的数组,支持 7 种数据的存取。

Buffer 是非线程安全的,多线程并发访问一个 Buffer 时应该进行同步。

Buffer 有读取和写入两种模式,刚创建时处于写入模式,模式之间可以进行切换。其模式切换关系如下图所示。

可写可读allocate()flip()get() / mark() / reset() / rewind()compact() / clear()put()

需要明确的是,一般情况下,Buffer 中并没有明确限制读取模式中 Buffer 只能读取,写入模式中只能写入。例如一个刚创建的 buf 也可以直接调用 get() 方法。不过按照这种模式的限制操作一个 Buffer 不容易使数据出错。另外,Buffer 中也提供了 asReadOnlyBuffer() 方法来基于原 Buffer 创建一个新的只读 Buffer。

Java NIO 缓冲区 Buffer

标签:int   XML   mes   e30   超过   city   核心   容器   固定   

原文地址:https://www.cnblogs.com/robothy/p/14223249.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!