定義:
ByteBuffer是Buffer的實現類之一,是一個通用的緩衝區,功能要比其他緩衝區子類多。支持直接內存。是一個抽象類。子類實現是HeapByteBuffer(非直接緩衝區子類),DirectByteBuffer(直接緩衝區子類)。
看此文前建議看看:
關於Buffer可以查看 Java NIO學習篇之緩衝區Buffer詳解
直接緩衝區:
以上是書《深入理解Java虛擬機》對直接內存的描述。簡單來說直接內存不是JVM內存,而是計算機真正的物理內存。
我們IO中有個步驟是:
讀:把內核緩衝區的數據複製到用戶緩衝區。
寫:把用戶緩衝區的數據複製到內核緩衝區。
而使用直接緩衝區可以使得內核緩衝區和用戶緩衝區映射到同一塊物理內存地址上,使得可以省略複製步驟,實現零拷貝,提高效率。
這裏它不是側重點,簡單瞭解下就好。
常用API詳解(是對應子類HeapByteBuffer的效果):
獲取ByteBuffer對象的API
//獲取ByteBuffer對象的方法
//1. 獲取非直接緩衝區的ByteBuffer,capacity參數指定緩衝區容量。
public static ByteBuffer allocate(int capacity);
//2. 通過傳入一個字節數組來獲取ByteBuffer對象。相當於把傳進來的字節數組封裝成一個ByteBuffer對象。
//如果傳進來的數組有數據的話,可以直接進行讀,此時ByteBuffer會處於讀模式。創建的初始ByteBuffer的
//limit=該數組的長度length,position=0,所以讀取的話會完全讀取該數組的。
public static ByteBuffer wrap(byte[] array);
//3. 通過傳入一個字節數組來獲取ByteBuffer對象。相當於把傳進來的字節數組封裝成一個ByteBuffer對象。並且可以指定position(用參數offset指定),limit(用length+offset指定)。
public static ByteBuffer wrap(byte[] array,int offset, int length)
///////////////以上三種方法獲取的都是非直接緩衝區/////////////
//4.獲取直接緩衝區,並用capacity指定緩衝區的大小。
public static ByteBuffer allocateDirect(int capacity)
public class ByteBufferDemo {
public static void main(String[] args) {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
System.out.println("============>>>allocate(int)<<<<==================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byte[] b1 = new byte[1024];
ByteBuffer byteBuffer1 = ByteBuffer.wrap(b1);
System.out.println("============>>>wrap(byte[])<<<<==================");
System.out.println("position = " + byteBuffer1.position());
System.out.println("limit = " + byteBuffer1.limit());
System.out.println("capacity = " + byteBuffer1.capacity());
byte[] b2 = new byte[1024];
ByteBuffer byteBuffer2 = ByteBuffer.wrap(b1,10,500);
System.out.println("============>>>wrap(byte[],int,int)<<<<==================");
System.out.println("position = " + byteBuffer2.position());
System.out.println("limit = " + byteBuffer2.limit());
System.out.println("capacity = " + byteBuffer2.capacity());
System.out.println("============>>>allocateDirect(int)<<<<==================");
ByteBuffer byteBuffer3 = ByteBuffer.allocateDirect(1024);
System.out.println("position = " + byteBuffer3.position());
System.out.println("limit = " + byteBuffer3.limit());
System.out.println("capacity = " + byteBuffer3.capacity());
}
}
執行結果:
對緩衝區寫數據的API
//往緩衝區中寫入一個字節的數據,遊標右移一位。返回緩衝區自身,可進行鏈式寫入。
public abstract ByteBuffer put(byte b);
//往緩衝區數組的某個位置寫入一個字節數據,返回緩衝區自身,可進行鏈式寫入。此操作不會使遊標移動。
public abstract ByteBuffer put(int index, byte b);
//往緩衝區中添加另一個緩衝區的數據,會讀取參數src的position到limit-1下標的數據。
//如果該src的可讀數據長度比調用該方法的可寫緩衝區的數據長度長的話,就會報錯。
public ByteBuffer put(ByteBuffer src);
//往緩衝區裏面添加一個字節數組,並可以指定src數組的偏移量和長度。
//添加之後緩衝區的position=oldPsition+length
public ByteBuffer put(byte[] src, int offset, int length);
//往緩衝區裏面添加一個字節數組,添加完後position=oldPsition+length
public final ByteBuffer put(byte[] src)
demo:
public static void testPut(){
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("==================>>>初始<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.put((byte) 5);
System.out.println("==================>>>ByteBuffer put(byte b)<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
byteBuffer.put(2,(byte) 5);
System.out.println("==================>>>put(int index, byte b)<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
//源緩衝區
ByteBuffer src = ByteBuffer.allocate(5);
src.put("hh".getBytes());
src.flip();
byteBuffer.put(src);
System.out.println("==================>>>put(ByteBuffer src)<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
byte[] bytes = new byte[5];
byteBuffer.put(bytes,1,3);
System.out.println("==================>>>put(byte[] src, int offset, int length)<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
byteBuffer.put(bytes);
System.out.println("==================>>>put(byte[] src)<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
}
結果:
獲取緩衝區數據的API
//讀取緩衝區的下一字節數據,position右移一位。
public abstract byte get();
//讀取緩衝區的指定下標字節數據,position不移動。
public abstract byte get(int index);
//讀取緩衝區的數據到dst數組,可以指定讀到dst的偏移量和讀取數據的長度。
//position右移length。
//返回自身,可鏈式調用
public ByteBuffer get(byte[] dst, int offset, int length);
//讀取緩衝區的數據到dst數組。
//position右移dst.length()。
//返回自身,可鏈式調用
public ByteBuffer get(byte[] dst);
demo:
public static void testGet(){
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
byteBuffer.put("helloworld".getBytes());
byteBuffer.flip();
System.out.println("==================>>>初始<<<=====================");
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byte b = byteBuffer.get();
System.out.println("==================>>>get()<<<=====================");
System.out.println(new String(new byte[]{b}));
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
byteBuffer.put("helloworld".getBytes());
byteBuffer.flip();
byte b1 = byteBuffer.get(2);
System.out.println("==================>>>get(int index)<<<=====================");
System.out.println(new String(new byte[]{b1}));
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
byteBuffer.put("helloworld".getBytes());
byteBuffer.flip();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
System.out.println("==================>>>get(byte[] dst, int offset, int length)<<<=====================");
System.out.println(new String(bytes));
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
byteBuffer.put("helloworld".getBytes());
byteBuffer.flip();
byte[] bytes1 = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes1,5,5);
System.out.println("==================>>>get(byte[] dst)<<<=====================");
System.out.println(new String(bytes1,5,5));
System.out.println("position = " + byteBuffer.position());
System.out.println("limit = " + byteBuffer.limit());
System.out.println("capacity = " + byteBuffer.capacity());
byteBuffer.clear();
}
結果:
其他API:
//返回一個只讀緩衝區,返回的緩衝區與原本的緩衝區不是同一個緩衝區,是不同的對象。
//與原本緩衝區的數據和元數據都一樣,只是他是隻讀的。
public ByteBuffer asReadOnlyBuffer();
//返回一個int緩衝區。其他類型的也差不多。
public IntBuffer asIntBuffer();
//將字節緩衝區的當前position加後面3位byte數據(共四位)轉換成一個int類型返回。
//遊標position右移4
public abstract int getInt();
//將字節緩衝區的i下標加後面3位byte數據(共四位)轉換成一個int類型返回。
//遊標不移動
public int getInt(int i)
//將value值存進緩衝區當前position+後3位,存進去。
//遊標position右移4
putInt(int value);
//將value值存進緩衝區index+後3位,存進去。
//遊標不移動
putInt(int index, int value)
//上面的操作其他類型的相關操作類似,只是轉成的byte數組長度不一樣,例如int會轉成4,long轉成8.//
//返回一個當前ByteBuffer 的副本。是一個新對象。
public ByteBuffer duplicate();
其他六種基本類型的緩衝區API與ByteBuffer的子集類似,有些只是多瞭解碼編碼,所以,只要學會ByteBuffer的API差不多等於學會了其他六種基本類型的API。