一、概述
Buffer是一个抽象类,位于java.nio包下,类声明如下:public abstract classBuffer
extends Object
Buffer是一个用于特定基本类型数据的容器。
缓冲区是特定基本类型元素的线性有限序列。除内容外,缓冲区的基本属性还包括容量、限制和位置:
缓冲区的容量 是它所包含的元素的数量。缓冲区的容量不能为负并且不能更改。
缓冲区的限制 是第一个不应该读取或写入的元素的索引。缓冲区的限制不能为负,并且不能大于其容量。
缓冲区的位置 是下一个要读取或写入的元素的索引。缓冲区的位置不能为负,并且不能大于其限制。
对于每个非 boolean 基本类型,此类都有一个子类与之对应。
传输数据
此类的每个子类都定义了两种获取 和放置 操作:
相对 操作读取或写入一个或多个元素,它从当前位置开始,然后将位置增加所传输的元素数。如果请求的传输超出限制,则相对获取 操作将抛出BufferUnderflowException
,相对放置 操作将抛出BufferOverflowException
;这两种情况下,都没有数据被传输。
绝对 操作采用显式元素索引,该操作不影响位置。如果索引参数超出限制,绝对获取 操作和放置 操作将抛出
。
IndexOutOfBoundsException
当然,通过适当通道的 I/O 操作(通常与当前位置有关)也可以将数据传输到缓冲区或从缓冲区传出数据。
做标记和重置
缓冲区的标记 是一个索引,在调用 reset
方法时会将缓冲区的位置重置为该索引。并非总是需要定义标记,但在定义标记时,不能将其定义为负数,并且不能让它大于位置。如果定义了标记,则在将位置或限制调整为小于该标记的值时,该标记将被丢弃。如果未定义标记,那么调用reset
方法将导致抛出
InvalidMarkException
。
不变式
位置、限制和容量值遵守以下不变式:0 <= 标记 <= 位置 <=限制
<= 容量
新创建的缓冲区总有一个 0 位置和一个未定义的标记。初始限制可以为 0,也可以为其他值,这取决于缓冲区类型及其构建方式。一般情况下,缓冲区的初始内容是未定义的。
清除、反转和重绕
除了访问位置、限制、容量值的方法以及做标记和重置的方法外,此类还定义了以下可对缓冲区进行的操作:
clear()
使缓冲区为一系列新的通道读取或相对放置 操作做好准备:它将限制设置为容量大小,将位置设置为 0。flip()
使缓冲区为一系列新的通道写入或相对获取 操作做好准备:它将限制设置为当前位置,然后将位置设置为 0。rewind()
使缓冲区为重新读取已包含的数据做好准备:它使限制保持不变,将位置设置为 0。
只读缓冲区
每个缓冲区都是可读取的,但并非每个缓冲区都是可写入的。每个缓冲区类的转变方法都被指定为可选操作,当对只读缓冲区调用时,将抛出 ReadOnlyBufferException
。只读缓冲区不允许更改其内容,但其标记、位置和限制值是可变的。可以调用其isReadOnly
方法确定缓冲区是否为只读。
线程安全
多个当前线程使用缓冲区是不安全的。如果一个缓冲区由不止一个线程使用,则应该通过适当的同步来控制对该缓冲区的访问。
调用链
指定此类中的方法返回调用它们的缓冲区(否则它们不会返回任何值)。此操作允许将方法调用组成一个链;例如,语句序列
b.flip(); b.position(23); b.limit(42);
可以由以下更紧凑的一个语句代替
b.flip().position(23).limit(42);
二、方法
1、public final intcapacity() 返回此缓冲区的容量。
2、public final int position() 返回此缓冲区的位置。
3、public finalBufferposition(int newPosition)
设置此缓冲区的位置。如果标记已定义且大于新的位置,则丢弃该标记。
参数:newPosition
- 新位置值;必须为非负且不大于当前限制
返回:此缓冲区
抛出:IllegalArgumentException
- 如果newPosition
不满足先决条件
4、public final intlimit() 返回此缓冲区的限制。
5、public finalBufferlimit(int newLimit)
设置此缓冲区的限制。如果位置大于新的限制,则将它设置为新限制。如果标记已定义且大于新限制,则丢弃该标记。
参数:newLimit
- 新限制值;必须为非负且不大于此缓冲区的容量
返回:此缓冲区
抛出:IllegalArgumentException
- 如果newLimit
不满足先决条件
6、public finalBuffermark()
在此缓冲区的位置设置标记。
7、public finalBufferreset()
将此缓冲区的位置重置为以前标记的位置。调用此方法不更改也不丢弃标记的值。
InvalidMarkException
- 如果尚未设置标记在使用一系列通道读取或放置 操作填充此缓冲区之前调用此方法。例如:
buf.clear(); // Prepare buffer for reading in.read(buf); // Read data
此方法不能实际清除缓冲区中的数据,但从名称来看它似乎能够这样做,这样命名是因为它多数情况下确实是在清除数据时使用。
9、public final Buffer flip()
反转此缓冲区。首先将限制设置为当前位置,然后将位置设置为 0。如果已定义了标记,则丢弃该标记。在一系列通道读取或放置 操作之后,调用此方法为一系列通道写入或相对获取 操作做好准备。例如:
buf.put(magic); // Prepend header
in.read(buf); // Read data into rest of buffer
buf.flip(); // Flip buffer
out.write(buf); // Write header + data to channel
当将数据从一个地方传输到另一个地方时,经常将此方法与 compact
方法一起使用。
10、public final int remaining() 返回当前位置与限制之间的元素数。
11、public final boolean hasRemaining() 告知在当前位置和限制之间是否有元素。
12、public abstract boolean
isReadOnly()
告知此缓冲区是否为只读缓冲区。
13、public abstract boolean
hasArray() 告知此缓冲区是否具有可访问的底层实现数组。如果此方法返回
true,则可以安全地调用 array
和 arrayOffset
方法。
14、public abstract
Object array() 返回此缓冲区的底层实现数组(可选操作)。此方法旨在使具有底层实现数组的缓冲区能更有效地传递给本机代码。具体子类为此方法提供更强类型的返回值。对此缓冲区内容进行修改将导致返回数组的内容被修改,反之亦然。调用此方法前应调用
hasArray
方法,以确保此缓冲区存在可访问的底层实现数组。
返回:此缓冲区的底层实现数组
抛出:ReadOnlyBufferException
- 如果此缓冲区存在底层实现数组,但它是只读的
UnsupportedOperationException
- 如果此缓冲区不存在可访问的底层实现数组
15、public abstract int
arrayOffset()
如果此缓冲区存在底层实现数组,那么缓冲区位置 p 对应于数组索引 p + arrayOffset()。
调用此方法前应调用 hasArray
方法,以确保此缓冲区存在可访问的底层实现数组。
- 返回:
- 此缓冲区数组中第一个缓冲区元素的偏移量
- 抛出:
ReadOnlyBufferException
- 如果此缓冲区存在底层实现数组,但它是只读的UnsupportedOperationException
- 如果此缓冲区不存在可访问的底层实现数组
16、public abstract boolean
isDirect() 告知此缓冲区是否为直接缓冲区。