内容目录
2.2 创建缓冲区
就像我们在图 2-1 所看到的那样,有七种主要的缓冲区类,每一种都具有一种Java语言中的非布尔类型的原始类型数据。(第8种也在图中显示出来,MappedByteBuffer
,是ByteBuffer
专门用于内存映射文件的一种特例。我们将会在第三章讨论内存映射)。这些类没有一种能够直接实例化。它们都是抽象类,但是都包含静态工厂方法用来创建相应类的新实例。 对于这一讨论,我们将以CharBuffer
类为例,但是对于其它六种主要的缓冲区类也是适用的:IntBuffer
,DoubleBuffer
,ShortBuffer
,LongBuffer
,FloatBuffer
,和ByteBuffer
。下面是创建一个缓冲区的关键函数,对所有的缓冲区类通用(要按照需要 替换类名):
public abstract class CharBuffer extends Buffer implements CharSequence, Comparable
{
// 这里仅列出部分API
public static CharBuffer allocate (int capacity)
public static CharBuffer wrap (char[] array)
public static CharBuffer wrap (char[] array, int offset, int length)
public final boolean hasArray()
public final char [] array()
public final int arrayOffset()
}
新的缓冲区是由分配或包装操作创建的。分配操作创建一个缓冲区对象并分配一个私有的空间来储存容量大小的数据元素。包装操作创建一个缓冲区对象但是不分配任何空间来储存数据元素。它使用您所提供的数组作为存储空间来储存缓冲区中的数据元素。
要分配一个容量为100个char
变量的Charbuffer
:
CharBuffer charBuffer = CharBuffer.allocate (100);
这段代码隐含地从堆空间中分配了一个char
型数组作为备份存储器来储存100个char
变量。 如果您想提供您自己的数组用做缓冲区的备份存储器,请调用wrap()
函数:
char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
这段代码构造了一个新的缓冲区对象,但数据元素会存在于数组中。这意味着通过调用put()
函数造成的对缓冲区的改动会直接影响这个数组,而且对这个数组的任何改动也会对这个缓冲区对象可见。带有offset
和length
作为参数的wrap()
函数版本则会构造一个按照您提供的offset
和length
参数值初始化位置和上界的缓冲区。这样做:
CharBuffer charbuffer = CharBuffer.wrap (myArray, 12, 42);
创建了一个position
值为 12,limit
值为54,容量为myArray.length
的缓冲区。
这个函数并不像您可能认为的那样,创建了一个只占用了一个数组子集的缓冲区。这个缓冲区可以存取这个数组的全部范围;offset
和length
参数只是设置了初始的状态。调用使用上面代码中的方法创建的缓冲区中的clear()
函数,然后对其进行填充,直到超过上界值,这将会重写数组中的所有元素。slice()
函数(2.3 节将会讨论)可以提供一个只占用备份数组一部分的缓冲区。
通过allocate()
或者wrap()
函数创建的缓冲区通常都是间接的(直接缓冲区会在2.4.2 节讨论)。间接的缓冲区使用备份数组,像我们之前讨论的,您可以通过上面列出的API 函数获得对这些数组的存取权。boolean
型函数hasArray()
告诉您这个缓冲区是否有一个可存取的备份数组。如果这个函数的返回true
,array()
函数会返回这个缓冲区对象所使用的数组存储空间的引用。
如果hasArray()函数返回false,不要调用array()函数或者arrayOffset()函数。如果您这样做了您会得到一个UnsupportedOperationException异常。如果一个缓冲区是只读的,它的备份数组将会是超出上界的,即使一个数组对象被提供给wrap()函数。
调用array()
函数或者arrayOffset()
会抛出一个ReadOnlyBufferException
异常,来阻止您得到存取权来修改只读缓冲区的内容。如果您通过其它的方式获得了对备份数组的存取权限,对这个数组的修改也会直接影响到这个只读缓冲区。只读缓冲区将会在 2.3 节讨论。
最后一个函数,arrayOffset()
,返回缓冲区数据在数组中存储的开始位置的偏移量(从数组头 0 开始计算)。如果您使用了带有三个参数的版本的 wrap()
函数来创建一个缓冲区,对于这个缓冲区,arrayOffset()
会一直返回 0,像我们之前讨论的那样。然而,如果您切分了由一个数组提供存储的缓冲区,得到的缓冲区可能会有一个非 0 的数组偏移量。这个数组偏移量和缓冲区容量值会告诉您数组中哪些元素是被缓冲区使用的。缓冲区的切分会在2.3 节讨论。 到现在为止,这一节所进行的讨论已经针对了所有的缓冲区类型。我们用来做例子的CharBuffer
提供了一对其它缓冲区类没有的有用的便捷的函数:
public abstract class CharBuffer extends Buffer implements CharSequence, Comparable
{
// 这里仅列出部分API
public static CharBuffer wrap (CharSequence csq)
public static CharBuffer wrap (CharSequence csq, int start, int end)
}
wrap()
函数创建一个只读的备份存储区是CharSequence
接口或者其实现的的缓冲区对象。(CharSequence
对象将在第五章讨论)。CharSequence
描述了一个可读的字符流 。 像JDK1.4中,三个标准的实现了CharSequence
接口的类:String
,StringBuffer
,和 CharBuffer
。wrap()
函数可以很实用地“缓冲”一个已有的字符数据,通过缓冲区的 API 来存取其中的内容。对于字符集解码(第六章)和正则表达式处理(第五章)这将是非常方便的。
CharBuffer charBuffer = CharBuffer.wrap ("Hello World");
三个参数的wrap()
函数版本使用start
和end
下标参数来描述传入的CharSequence
对象的子序列。这是一个方便的类似于调用了CharSequence.subsequence()
函数的转换。start
参数是序列中使用的第一个字符,end
是最后一个字符的下标值加1。
0 条评论
撰写评论