初出 JAVA PRESS Vol.29

Java API ダイジェスト

java.nio.ByteBuffer

バッファはプリミティブ型に特化したコンテナクラスですが、その中でもByteBufferクラスはチャネルと共に使用されるなど最も使用頻度の高いバッファです。

その他のプリミティブ型に対応したバッファも使用法は基本的に同じです。


byte型に特化したコンテナクラス

ByteBufferクラスはBufferクラスで定義された基本機能と、自身で定義する要素へのアクセスメソッドなどが定義されています。その中でも主だったものを紹介します。

ByteBufferオブジェクトを生成にはallocateメソッドを使用します。ヒープ外のメモリにバッファを割り付けるにはallocateDirectメソッド、byte配列を使用して生成する場合にはwrapメソッドを使用します。

生成

バッファのpositon, limitプロパティを取得、設定するにはposition、limitメソッドを使用します。また、プロパティの初期化にはclearメソッド、入れ替えにはflipメソッドを使用します。

position, limitに関する操作

要素の読み込みにはgetメソッドを使用し、書き込みにはputメソッドを使用します。

要素へのアクセス

高性能なbyte型のコンテナクラス

生成

public static ByteBuffer allocate(int capacity)

public static ByteBuffer allocateDirect(int capacity)

public static ByteBuffer wrap(byte[] array) throws IndexOutOfBoundsException

 

ByteBufferオブジェクトを生成するにはstaticメソッドのallocateを使用します。引数のcapacityはバッファの容量です。

New I/Oでは、Javaのヒープ外にバッファの割り当てを行うダイレクトバッファを使用できます。これを生成するにはallocateDirectメソッドを使用します。

ダイレクトバッファの生成はByteBufferクラスしか行えませんが、他のバッファへの変換メソッドasXXXXBuffer (XXXXはプリミティブ型名) を使用することで、他のバッファでもダイレクトバッファを使用することができます。

wrapメソッドは引数のbyte配列を使用してバッファを生成します。生成されたバッファは内部の要素として引数の配列を使用するため、要素を変更するとbyte配列も変更されます。また、byte列に変更を加えると、バッファもそれに応じて変更されます。

リスト1に3種類の生成例を示しました。

リスト 1 生成の例

    // 容量が10のバッファ
    ByteBuffer buffer = ByteBuffer.allocate(10);
 
    // 容量が10のダイレクトバッファ
    ByteBuffer directBuffer = ByteBuffer.allocateDirect(10); 
  
    // 配列を使用したバッファの生成
    byte[] array = new byte[]{0x01, 0x02, 0x03, 0x04};
    ByteBuffer buffer2 = ByteBuffer.wrap(array);

position, limitに関する操作

public int position()
public Buffer position(int newPosition)

public int limit()
public Buffer limit(int newLimit)

public Buffer clear()

public Buffer flip()

バッファは図1に示した3つのプロパティを持ちます。

positionは要素のアクセス位置を示します。読み込み・書き込みを行うと、そのデータ量に応じてpositionが移動します。

positionの最大値がlimitです。capacityはバッファの容量を表します。したがって、これらの関係は0 <= position <= limit <= capacityとなります。

capacityは不変ですが、limitとpositionは変更できます。positionメソッド、limitメソッドとも引数がない場合は値を取得、intの引数がある場合は値を設定します。ただし、上述の関係を破るような値を設定するとIllegalArgumentException例外が発生します。

これ以外にもposition、limitを操作するメソッドがあります。clearメソッドはプロパティの初期化、つまりposition=0、limit=capacityとします(図2)。flipメソッドはlimitをpositionの値として、positionは0にします(図3)。この2つのメソッドの使用例はByteChannelインタフェースの使用例を参照してください。

Buffer のプロパティ

図1 バッファのプロパティ

clear メソッド

図2 clearメソッド

flip メソッド

図3 flipメソッド

要素へのアクセス

public byte get()
public ByteBuffer get(byte[] dst)
public ByteBuffer get(byte[] dst, int offset, int length)
public ByteBuffer get(int index)

public ByteBuffer put(byte b)
public ByteBuffer put(byte[] src)
public ByteBuffer put(byte[] srt, int offset, int length)
public ByteBuffer put(ByteBuffer src)
public ByteBuffer put(int index, byte b)

バッファの要素を読み込むには get メソッドを使用します。getメソッドは引数の違いにより4種類ありますが、シーケンシャルアクセスを行うものと、ランダムアクセスを行うものに大別できます。シーケンシャルアクセスは引数にindexがないものです。

シーケンシャルアクセスではpositionから読み込みを行います。引数のない場合、1バイト読み込み、positionを1進めます。

引数が配列のみの場合、配列の長さ分読み込み、positionをその分進めます。offsetとlengthが指定してある場合、positionの位置からlengthバイトを読み込み、dst[offset]から格納します。positionはlength分進みます。

ランダムアクセスを行うものは引数にindexがあるgetメソッドです。indexの位置の要素を1バイト読み込みますが、positionは変更しません。

書き込みもgetメソッドと同様にシーケンシャルアクセスとランダムアクセスに大別できます。

bが引数のputメソッドは、position位置にbを書き込み、positionを1進めます。byte配列が引数のものは、配列の内容をバッファに書き込みます。positionは配列長進みます。offsetとlengthが指定されている場合は、dst[offset]からlengthバイト書き込みます。positionはlength進みます。

ByteBufferオブジェクトのsrcが引数の場合、srcのpositionからlimitまでの要素を書き込みます。positionはsrcのlimit-position分だけ進みます。

引数にindexを使用しているのが、ランダムアクセスのputメソッドです。indexの位置にbを書き込みますが、positionは変化しません。

(2003.03)