第二章 缓冲区(9)

来源:互联网 发布:斗鱼抽奖 知乎 编辑:程序博客网 时间:2024/05/18 00:07

2.2 创建buffer对象

就像我们在图2.1中看到的那样,NIO中存在7buffer的基本类型,对应于java中除了boolean的所有java基本数据类型(第八种buffer类型是MappedByteBuffer,它是ByteBuffer处理内存映射文件的特殊形式,我们将在第三章中讨论内存映射文件)。这些类型都是不能直接实例化的。它们都是抽象类,但是他们都有静态的工厂类来创建各种类型的对象。

对于下面的讨论,我们将使用CharBuffer作为例子,当然它也适用于其他的六种buffer类型:IntBufferDoubleBufferShortBufferLongBufferFloatBufferByteBuffer。下面是创建CharBuffer对象的主要方法,只要替代为名字就跟其他buffer类型一样。

public abstract class CharBuffer 

extends Buffer implements CharSequence,Comparable{

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();

}

可以通过allocate方法和wrap方法来创建新的buffer对象。Allocate方法创建一个buffer对象,开辟capacity个元素的私有空间。Wrap方法会创建一个buffer对象,但是不会开辟任何数据空间。它将使用你提供的数组作为后备空间来保存数据。

为了开辟100个空间的CharBuffer对象,可以使用下面的代码:

CharBuffer charBuffer=CharBuffer.allocate(100);

它将暗中从堆中分配100个单元作为对象的后备空间来存储100个字符。

如果你想提供自己的数组来作为CharBuffer的后备空间,可以使用wrap方法来实现:

char[] myArray=new char[100];

CharBuffer charBuffer=CharBuffer.wrap(myArray);

这些代码将产生一个新的CharBuffer对象,但是数据将会保存在你提供的数组中。这也意味着你对CharBuffer对象做像put方法的更改将直接反应在你的数组上,你对数组的任何更改也会反映在CharBuffer对象上。使用offsetlength参数版本的wrap方法将会创建一个根据你的参数设定的positionlimitbuffer对象。下面的代码:

CharBuffer charBuffer=CharBuffer.wrap(myArray,12,24);

将会创建一个position=12limit=24capacity=myArray.lengthCharBuffer对象。这个方法并不会像你想象的那样只占用你提供数组的一部分。Buffer对象将使用数组的全部空间;offsetlimit参数只会设置CharBuffer的初始值。向这个buffer对象调用clear方法,然后填充数据直到bufferposition到达limit,就会使数组的数据被全部覆盖。2.3小节中将讨论slice方法产生一个只影响一部分数据的buffer对象。

通过allocate方法和wrap方法创建的Buffer对象都不是内核中的数据缓冲区,这些方法创建的缓冲区都存在后备数组,因而我们能够通过上面列出的API获取对这些数组的访问权。返回boolean值的hasArray方法可以返回这个buffer对象是否拥有后备数组,如果hasArray返回true,你就能从array方法得到buffer对象的后备数组引用。

如果hasArray方法返回false,你就不能使用array或者arrayOffset方法,否则你将得到一个UnsupportedOperationException异常。如果一个buffer对象是只读的,它的后备数组也是禁止访问的,尽管这个对象是通过wrap方法生成的。对只读buffer对象调用array或者arrayOffset方法将导致ReadOnlyException异常的抛出,当然这样是为了保证你不对只读的buffer对象进行访问或者修改。如果你拥有其他的方式来获得buffer对象的后备数组引用,你对数组的修改将会反映到只读的buffer对象上。关于只读buffer对象将在2.3节中进行详细的讨论。

到目前为止,这节讨论的内容适用于所有的其他buffer类型。但是我们作为例子的CharBuffer类型还提供了一个其他buffer类型不具备的方便使用的方法。

public abstract class CharBuffer 

extends Buffer implements CharSequence,Comparable{

public static CharBuffer wrap(CharSequence csq);

public static CharBuffer wrap(CharSequence csq,int start,int end);

}

上面这些wrap方法创建了一些只读buffer类型的视图,得到的buffer对象的后备数组是CharSequence对象或者是CharSequence对象的子集(在第五章中我们对CharSequence对象进行详细的讨论)。CharSequence类描述了一系列可读取的字符串序列。在JDK1.4版本中,三个标准类实现了CharSequence接口:StringStringBufferCharBuffer。这个版本的wrap方法对于缓冲已经存在的字符串数据,然后使用BufferAPI来访问非常方便。这样做对于字符集处理(见第六章)和正则表达式处理(见第五章)非常便利。

CharBuffer charBuffer=CharBuffer.wrap("Hello World");

带三个参数形式的wrap方法,将索引从startendCharSequence传递给CharBuffer。它跟CharSequence.subsequence()方法一样方便。Start参数表示字符串序列的第一个字符,end参数表示最后一个字符加上一的位置。

原创粉丝点击