`
美丽的小岛
  • 浏览: 298967 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Buffer类与ByteBuffer类(来自JDK)

    博客分类:
  • java
 
阅读更多

1.         Bufferpublic abstract class Buffer extends Object

直接已知子类:

ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer

一个用于特定基本类型数据的容器。

缓冲区是特定基本类型元素的线性有限序列。除内容外,缓冲区的基本属性还包括容量、限制和位置:

缓冲区的容量 是它所包含的元素的数量。缓冲区的容量不能为负并且不能更改。

缓冲区的限制 是第一个不应该读取或写入的元素的索引。缓冲区的限制不能为负,并且不能大于其容量。

缓冲区的位置 是下一个要读取或写入的元素的索引。缓冲区的位置不能为负,并且不能大于其限制。

对于每个非 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);

2.         public abstract class ByteBuffer extends Buffer implements Comparable<ByteBuffer> 字节缓冲区。

此类针对字节缓冲区定义了以下六类操作:

  • 读写单个字节的绝对和相对 get put 方法;
  • 将此缓冲区的连续字节序列传输到数组中的相对批量 get 方法;
  • byte 数组或其他字节缓冲区中的连续字节序列传输到此缓冲区的相对批量 put 方法;
  • 读写其他基本类型值,并按照特定的字节顺序在字节序列之间转换这些值的绝对和相对 get put 方法;
  • 创建视图缓冲区 的方法,这些方法允许将字节缓冲区视为包含其他基本类型值的缓冲区;
  • 对字节缓冲区进行 compactingduplicating slicing 的方法。

字节缓冲区可以通过 allocation 方法创建,此方法为该缓冲区的内容分配空间,或通过 wrapping 方法将现有的 byte 数组包装到缓冲区中来创建。

直接 非直接缓冲区

字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。

直接字节缓冲区可以通过调用此类的 allocateDirect 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。

直接字节缓冲区还可以通过 mapping 将文件区域直接映射到内存中来创建。Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。

字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。

访问二进制数据

此类定义了除 boolean 之外,读写所有其他基本类型值的方法。这些基本值可以根据缓冲区的当前字节顺序与字节序列互相进行转换,并可以通过 order 方法获取和修改。特定的字节顺序由 ByteOrder 类的实例表示。字节缓冲区的初始顺序始终是 BIG_ENDIAN

为了访问异类二进制数据(即其他类型的值的序列),此类还针对每种类型定义了一系列绝对和相对的 get put 方法。例如,对于 32 位浮点值,此类定义了以下方法:

 float  getFloat()

 float  getFloat(int index)

  void  putFloat(float f)

  void  putFloat(int index, float f)

并针对 charshortintlong double 等类型定义了相应的方法。绝对 get put 方法的 index 参数是根据字节定义的,而不是根据所读写的类型定义的。

为了访问同类二进制数据(即相同类型的值的序列),此类还定义了可以为指定类型的缓冲区创建视图 的方法。视图缓冲区 只是其内容受该字节缓冲区支持的另一种缓冲区。字节缓冲区内容的更改在视图缓冲区中是可见的,反之亦然;这两种缓冲区的位置、限制和标记值都是独立的。例如,asFloatBuffer 方法将创建 FloatBuffer 类的一个实例,该类受在其上调用该方法的字节缓冲区的支持。该类将为 charshortintlong double 等类型定义相应的视图创建方法。

与上述特定于类型的 get put 方法系列相比,视图缓冲区有以下三大主要优势:

  • 视图缓冲区不是根据字节进行索引,而是根据其特定于类型的值的大小进行索引;
  • 视图缓冲区提供了相对批量 get put 方法,这些方法可在缓冲区和数组或相同类型的其他缓冲区之间传输值的连续序列;
  • 视图缓冲区可能更高效,这是因为,当且仅当其支持的字节缓冲区为直接缓冲区时它才是直接缓冲区。

视图缓冲区的字节顺序固定为创建该视图时其字节缓冲区的字节顺序。

调用的链接

指定此类中的方法(它们不返回其他值),以返回这些方法被调用时所在的缓冲区。这允许对方法调用进行链接。 例如,语句序列

 bb.putInt(0xCAFEBABE);

 bb.putShort(3);

 bb.putShort(45);

可以由以下单个语句替换

 bb.putInt(0xCAFEBABE).putShort(3).putShort(45);

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics