1.简介
Buffer针对除boolean之外的每个基本类型数据都有一个实现类,即ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer。
它们的基本使用方法已经在Buffer中介绍过了。
1)视图缓冲区
ByteBuffer可以通过方法将字节缓冲区视为包含其他基本类型值的缓冲区。
视图缓冲区 只是其内容受该字节缓冲区支持的另一种缓冲区。字节缓冲区内容的更改在视图缓冲区中是可见的,反之亦然;这两种缓冲区的位置、限制和标记值都是独立的。
2)直接与 非直接缓冲区
字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
直接字节缓冲区可以通过调用此类的 allocateDirect 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。
直接字节缓冲区还可以通过 mapping 将文件区域直接映射到内存中来创建。Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。
字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。
其它类型的缓冲区要么是直接的,要么是非直接的。通过此类的 wrap 方法创建的缓冲区将是非直接的。当且仅当字节缓冲区本身为直接时,作为字节缓冲区的视图创建的缓冲区才是直接的。通过调用 isDirect 方法可以确定字符缓冲区是否为直接的。
3)字节缓冲区的字节顺序
字节缓冲区定义了除 boolean 之外,读写所有其他基本类型值的方法。这些基本值可以根据缓冲区的当前字节顺序与字节序列互相进行转换,并可以通过 order 方法检索和修改。特定的字节顺序由 ByteOrder 类的实例表示。字节缓冲区的初始顺序始终是 BIG_ENDIAN。
2.实例
package com.siyuan.test.jdk.nio;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.InvalidMarkException;
public class ByteBufferTest {
/**
* @param args
*/
public static void main(String[] args) {
ByteBuffer bBuffer = ByteBuffer.allocate(15);
System.out.println(getBufferStatus(bBuffer));
CharBuffer cBuffer = bBuffer.asCharBuffer();
System.out.println(getBufferStatus(cBuffer));
System.out.println("通过bBuffer写入数据");
while ((bBuffer.remaining() / 2) >= 1) {
bBuffer.putChar('b');
}
System.out.println(getBufferStatus(bBuffer));
System.out.println(getBufferStatus(cBuffer));
System.out.println("通过cBuffer读取内容");
while (cBuffer.hasRemaining()) {
System.out.print(cBuffer.get());
}
System.out.println();
System.out.println(getBufferStatus(bBuffer));
System.out.println(getBufferStatus(cBuffer));
}
public static final String getBufferStatus(Buffer buffer) {
StringBuilder str = new StringBuilder();
str.append("容量:").append(buffer.capacity())
.append(",位置:").append(buffer.position())
.append(",限制:").append(buffer.limit());
boolean markExist = false;
try {
int position = buffer.position();
buffer.reset();
markExist = true;
buffer.position(position);
} catch(InvalidMarkException e) {
}
str.append(",存在标志: ").append(markExist);
return str.toString();
}
}
运行结果:
容量:15,位置:0,限制:15,存在标志: false
容量:7,位置:0,限制:7,存在标志: false
通过bBuffer写入数据
容量:15,位置:14,限制:15,存在标志: false
容量:7,位置:0,限制:7,存在标志: false
通过cBuffer读取内容
bbbbbbb
容量:15,位置:14,限制:15,存在标志: false
容量:7,位置:7,限制:7,存在标志: false
3.参考资料
JDK文档,Thing IN JAVA