您的浏览器过于古老 & 陈旧。为了更好的访问体验, 请 升级你的浏览器
Ready 发布于2013年08月13日 07:55

原创 Java nio入门教程详解(六)

2028 次浏览 读完需要≈ 6 分钟

内容目录

2.3 复制缓冲区

如我们刚刚所讨论的那样,可以创建描述从外部存储到数组中的数据元素的缓冲区对象。但是缓冲区不限于管理数组中的外部数据。它们也能管理 其他缓冲区 中的外部数据。当一个管理其他缓冲器所包含的数据元素的缓冲器被创建时,这个缓冲器被称为视图缓冲器。大多数的视图缓冲器都是ByteBuffer(参见 2.4.3 节)的视图。在继续前往字节缓冲器的细节之前,我们先将注意力放在所有存储器类型的共同视图上。

视图存储器总是通过调用已存在的存储器实例中的函数来创建。使用已存在的存储器实例中的工厂方法意味着视图对象为原始存储器的内部实现细节私有。数据元素可以直接存取,无论它们是存储在数组中还是以一些其他的方式,而不需经过原始缓冲区对象的 get()/put()API。如果原始缓冲区是直接缓冲区,该缓冲区的视图会具有同样的效率优势。映像缓冲区也是如此(将于第三章讨论)。

在这一章节中,我们将再次以CharBuffer为例,但同样的操作可被用于任何基本的缓 冲区类型(参见图 2.1)。

public abstract class CharBuffer extends Buffer implements CharSequence, Comparable
{
// 这里仅列出部分API
public abstract CharBuffer duplicate();
public abstract CharBuffer asReadOnlyBuffer();
public abstract CharBuffer slice();
}

duplicate()函数创建了一个与原始缓冲区相似的新缓冲区。两个缓冲区共享数据元素,拥有同样的容量,但每个缓冲区拥有各自的位置,上界和标记属性。对一个缓冲区内的数据元素所做的改变会反映在另外一个缓冲区上。这一副本缓冲区具有与原始缓冲区同样的数据视图。如果原始的缓冲区为只读,或者为直接缓冲区,新的缓冲区将继承这些属性。直接缓冲区将在 2.4.2 节中讨论。

复制一个缓冲区会创建一个新的Buffer对象,但并不复制数据。原始缓冲区和副本都会操作同样的数据元素。

缓冲区及其副本之间的联系如图 2.12 所示。这是如下文所示的代码产生的:

CharBuffer buffer = CharBuffer.allocate (8);
buffer.position (3).limit (6).mark().position (5);
CharBuffer dupeBuffer = buffer.duplicate();
buffer.clear();

图 2-12 复制一个缓冲区

您可以使用asReadOnlyBuffer()函数来生成一个只读的缓冲区视图。这与duplicate()相同,除了这个新的缓冲区不允许使用put(),并且其isReadOnly()函数将会返回true。对这一只读缓冲区的put()函数的调用尝试会导致抛出ReadOnlyBufferException异常。

如果一个只读的缓冲区与一个可写的缓冲区共享数据,或者有包装好的备份数组,那么对这个可写的缓冲区或直接对这个数组的改变将反映在所有关联的缓冲区上,包括只读缓冲区。

分割缓冲区与复制相似,但slice()创建一个从原始缓冲区的当前位置开始的新缓冲区,并且其容量是原始缓冲区的剩余元素数量(limit-position)。这个新缓冲区与原始缓冲区共享一段数据元素子序列。分割出来的缓冲区也会继承只读和直接属性。图 2-13 显示了以与下面代码相似的代码所生成的分割缓冲区:

CharBuffer buffer = CharBuffer.allocate (8);
buffer.position (3).limit (5);
CharBuffer sliceBuffer = buffer.slice();

图 2-13 创建分割缓冲区

要创建一个映射到数组位置12-20(9个元素)的buffer对象,应使用下面的代码实现:

char [] myBuffer = new char [100];
CharBuffer cb = CharBuffer.wrap (myBuffer);
cb.position(12).limit(21);
CharBuffer sliced = cb.slice();

更详细关于视图buffer的讨论参见2.4.3节。

Java nio入门教程详解(七)

  • CodePlayer技术交流群1
  • CodePlayer技术交流群2

0 条评论

撰写评论