1. ByteBuffer の設計は抽象クラスです#
主な実装クラスは次のとおりです:
HeapByteBuffer ヒープ ByteBuffer JVM 内のヒープメモリを使用します --> 読み書きの効率が低く、GC の影響を受けます
2. MapperByteBuffer(抽象クラス、DirectByBuffer という実装クラスもあります) OS メモリを使用します --> 読み書きの効率が高く、GC の影響を受けません。ただし、明示的に解放しない場合、メモリリークの原因となります
取得方法#
Bytebuffer.allocate (10); // スペースを割り当てると、動的に調整することはできません
encode()
コア構造#
ByteBuffer は、配列のような構造であり、この構造には 3 つの主要な状態が含まれています
- Capacity
バッファの容量、配列のサイズに似ています- Position
バッファの現在のインデックス、読み取り操作時にどの位置まで読み取ったか、書き込み操作時にどの位置まで書き込んだかを記録します。0 から始まり、読み取るたびにインデックスは + 1 されます- Limit
読み書きの制限、読み取り操作時に読み取れるバイト数を設定し、書き込み操作時に書き込めるバイト数を設定します
読み書きモードとは、本質的にはこれらの状態の変化です。主に Position と Limit が Buffer の読み書きデータ領域を決定します。
以下は、容量、制限、位置の状態変化を図とコードで表したものです
@Test
public void test1(){
ByteBuffer buffer = ByteBuffer.allocate(10);
// 新しいbufferの状態
System.out.println("buffer.capacity() = " + buffer.capacity()); // 10
System.out.println("buffer.position() = " + buffer.position()); // 0
System.out.println("buffer.limit() = " + buffer.limit()); // 10
}
@Test
public void test2(){
ByteBuffer buffer = ByteBuffer.allocate(10);
// データをいくつか保存して、状態を見てみましょう
buffer.put(new byte[]{'a','b','c','d'});
System.out.println("buffer.capacity() = " + buffer.capacity()); // 10
System.out.println("buffer.position() = " + buffer.position()); // 4
System.out.println("buffer.limit() = " + buffer.limit()); // 10
}
@Test
public void test3(){
ByteBuffer buffer = ByteBuffer.allocate(10);
// データをいくつか保存して
buffer.put(new byte[]{'a','b','c','d'});
// 読み取りモードに切り替えて、状態を見てみましょう
buffer.flip();
System.out.println("buffer.capacity() = " + buffer.capacity()); // 10
System.out.println("buffer.position() = " + buffer.position()); // 0
System.out.println("buffer.limit() = " + buffer.limit()); // 4
}
@Test
public void test4(){
ByteBuffer buffer = ByteBuffer.allocate(10);
// データをいくつか保存して
buffer.put(new byte[]{'a','b','c','d'});
// 書き込みモードに切り替えて、状態を見てみましょう
buffer.clear();
System.out.println("buffer.capacity() = " + buffer.capacity()); // 10
System.out.println("buffer.position() = " + buffer.position()); // 0
System.out.println("buffer.limit() = " + buffer.limit()); // 10
}
@Test
public void test5(){
ByteBuffer buffer = ByteBuffer.allocate(10);
// データをいくつか保存して
buffer.put(new byte[]{'a','b','c','d'});
// 2つのデータを読み取る
buffer.flip();
byte b = buffer.get();
byte b2 = buffer.get();
System.out.println("buffer.capacity() = " + buffer.capacity()); // 10
System.out.println("buffer.position() = " + buffer.position()); // 2
System.out.println("buffer.limit() = " + buffer.limit()); // 4
// compactを使用して書き込みモードに切り替えて、状態を見てみましょう
buffer.compact();
System.out.println("buffer.capacity() = " + buffer.capacity()); // 10
System.out.println("buffer.position() = " + buffer.position()); // 2
System.out.println("buffer.limit() = " + buffer.limit()); // 10
/* 結果
* buffer.capacity() = 10
buffer.position() = 2
buffer.limit() = 4
buffer.capacity() = 10
buffer.position() = 2
buffer.limit() = 10
* */
}
最後にまとめると#
Buffer にデータを書き込む前に書き込みモードを設定する必要があります
- 書き込みモード
- 新しく作成した Buffer は自動的に書き込みモードになります
- clear、compact メソッドを呼び出した場合
Buffer からデータを読み取る前に読み取りモードを設定する必要があります
2. 読み取りモード
- flip メソッドを呼び出した場合