ByteBuffer 使用

ByteBuffer 使用

  • 1 java.nio包中的類定義的緩沖區類型
  • 2 緩沖區常用屬性
    • 2.1緩沖區的容量(capacity)
    • 2.2 緩沖區的位置(position)
    • 2.3 緩沖區的限制(limit)
    • 2.4 緩沖區的標記(mark)
    • 2.5 剩余容量 remaining/hasRemaining
  • 3 緩沖區常用方法
    • 3.1 創建緩沖區
      • 3.1.1 allocate方法
      • 3.1.2 wrap通過封裝數組來創建緩沖區
    • 3.2 創建視圖緩沖區
    • 3.3. 復制緩沖區 duplicate
    • 3.4 切分緩沖區slice
    • 3.5 標記和重置mark和reset
    • 3.6 翻轉flip
    • 3.7 清除clear
    • 3.8 壓縮compact
    • 3.9 rewind(倒回)
    • 3.10 寫數據
    • 3.11 讀數據
  • 4 常用使用方式
    • 4.1 讀寫范式
    • 4.2 與字符串之間的轉換
  • 參見java7入門經典

1 java.nio包中的類定義的緩沖區類型

描述
ByteBuffer用來存儲 byte 類型值的緩沖區,也可以在這種緩沖區中存儲任意其他基本類型的進制值(boolean 類型除外)。存儲的每個二進制值在緩沖區中占據的字節長度根據類型長度決定char 或short 類型值占據2字節int 類型值占據4字節,等等
CharBuffer只存儲char類型值的緩沖區
ShortBuffer只存儲short 類型值的緩沖區
IntBuffer只存儲int類型值的緩沖區
LongBuffer只存儲 long 類型值的緩沖區
Doublebuffer只存儲double類型值的緩沖區

雖然有不同的類可以定義緩沖區,但是只使用 BvteBuffer 類型的緩沖區來讀寫其他類型的緩沖區被稱為視圖緩沖區,因為通常將它們創建為已有 ByteBuffer 類型緩沖區的視圖視圖緩沖區提供了一種容易的方式可以將各種類型的數據項從 ByteBuffer 中讀出或者寫入到其中

2 緩沖區常用屬性

在這里插入圖片描述

2.1緩沖區的容量(capacity)

緩沖區的容量是指緩沖區所能包含的值的最大數目而不是字節數目(除ByteBuffer外)創建緩沖區時,緩沖區的容量是固定的并且不能在隨后進行修改。通過調用從 Buffer 類繼承而來的 capacity0方法,可以獲取 int 類型的緩沖區對象的容量。

2.2 緩沖區的位置(position)

位置(position)是指可用于讀或寫的下一個緩沖區元素的索引位置

2.3 緩沖區的限制(limit)

限制(limit)是指緩沖區中第一個不應該被讀或寫的值的索引位置,所以從 position 所指的元素到 limit-1所指的元素都可以被讀取或寫入。如果想要填充緩沖區,位置必須是零,因為這是第一個數據項所要存儲的位置,而且限制必須等于緩沖區的容量,因為最后一個數據項必須存儲到緩沖區的最后一個元素中,值為 capacity-1。

2.4 緩沖區的標記(mark)

標記(mark)記錄當前position的值, 默認值-1。和reset方法結合使用,position被改變后,可以通過調用reset() 方法恢復到mark的位置

2.5 剩余容量 remaining/hasRemaining

//Returns the number of elements between the current position and the limit.
//Returns:The number of elements remaining in this buffer
public final int remaining() {return limit - position;}
//Tells whether there are any elements between the current position and the limit.
public final boolean hasRemaining() {return position < limit;}

3 緩沖區常用方法

3.1 創建緩沖區

3.1.1 allocate方法

定義緩沖區的這些類都沒有可用的公共構造函數。作為替代,可以使用靜態的工廠方法來創建緩沖區。通常會通過調用類的靜態 allocate0方法來創建 ByteBuffer 類型的緩沖區對象。將int類型值作為參數傳入定義緩沖區容量的方法一一緩沖區必須加載的最大字節數。

//創建緩沖區(java 的堆內存)位置為0并且容量為 1024,限制未1024
ByteBuffer buf = ByteBuffer.allocate(1024);
//Allocates a new direct byte buffer.操作系統直接內存(非java堆內存,創建成本高,如果進行IO、Socket操作,讀取效率要高)
ByteBuffer bufdir = ByteBuffer.allocateDirect(1024);

當使用緩沖區類的 allocate0方法創建新緩沖區時,位置為零并且限制被設置為新緩沖區的容量

3.1.2 wrap通過封裝數組來創建緩沖區

通過調用靜態 wrap()方法中的一種來封裝已有的與緩沖區元素類型相同的數組,也能創建緩沖,使用這種方法創建的緩沖區已經包含數組中的數據。可以通過封裝 bytel類型的數組來創建ByteBuffer 對象。
當通過封裝數組來創建緩沖區時,緩沖區對象沒有自己的內存來存儲數據。緩沖區被放在用來定義它的數組的背后,所以對緩沖區中值的修改也會修改數組,反之也一樣。緩沖區的容量和限制被設置為數組的長度,位置為零

  • 無參wrap()
byte[] bytes= {1,2,3};
ByteBuffer buffer = ByteBuffer.wrap(bytes);
  • 有參 wrap(byte[] array, int offset, int length)
  String saying = "Handsome is as handsome does.";// Get string as byte arraybyte[] array = saying.getBytes();ByteBuffer buf = ByteBuffer.wrap(array, 914);

緩沖區的容量是 array.length,并且位置被設置為第二個參數的值 9。第三個參數設定要讀或寫的緩沖區元素的數目,這個值與位置相加就可以定義緩沖區的限制。

3.2 創建視圖緩沖區

// Buffer of 1024 bytes capacity
ByteBuffer buf = ByteBuffer.allocate(20);
buf.put((byte)1);
buf.put((byte)2);
// Now create a view buffer,
IntBuffer intBuf  buf.asIntBuffer();

視圖緩沖區的內容都起始于原始字節緩沖區的當前位置。視圖緩沖區本身的位置被初始設置為零,而且容量和限制被設置為由原始字節緩沖區剩余的字節數(limit-position)除以視圖緩沖區存儲的元素類型所占的字節數目而得到的值。視圖緩沖區 的position、limit 與原始字節緩沖區position、limit 相互獨立。
在這里插入圖片描述

3.3. 復制緩沖區 duplicate

通過調用緩沖區的 duplicate()方法可以復制任何討論過的緩沖區。該方法返回一個指向緩沖區的引用,其類型與原始緩沖區一樣,并且共享原始緩沖區的內容和內存。復制緩沖區與原始緩沖區擁有同樣的容量、位置和限制(duplicate時刻只是值一樣,兩個彼此獨立)。但是,雖然對復制內容的修改會反映到原始緩沖區,而且反之也一樣,但是原始緩沖區與復制緩沖區的位置和限制都彼此獨立。使用復制緩沖區的一種情況是當并行訪問緩沖區的不同部分,這使得在復制緩沖區中,能以不影響原始緩沖區的任何方式來提取訪問緩沖區內容的不同部分。
因此,復制緩沖區實際上并不真的是內存中的一個新緩沖區,它只是一個新對象,能提供訪問用于緩存數據的同一塊內存的另一種方式。duplicate0方法返回的指向新對象的通用類型與原始對象的一樣,但是沒有任何獨立的數據存儲。這里只是共享屬于原始緩存區對象的內存,但是使用獨立的位置和限制值。

3.4 切分緩沖區slice

由 slice()方法生成的緩沖區會映射到原始緩沖區的一部分-從當前位置開始直到 imit-1的所有元素(包括 limit-1 處的元素)。當然,如果原始緩沖區對象的位置為零并且限制與容量相等,那么slice0方法將產生與 duplicate0方法一樣的結果一緩沖區內存被共享。切分緩沖區實際上是通過兩個或更多的途徑來給予訪問緩沖區中給定部分數據的權限,使得切分后的每個緩沖區都有自己獨立的位置和限制(調用slice后,新的緩沖區position=0,limit/capacity=原始緩沖區limit-position)
在這里插入圖片描述

3.5 標記和重置mark和reset

對緩沖區使用標記屬性是為了記錄緩沖區中想要稍后返回的特定索引位置。通過調用從 Buffer類繼承而來的緩沖區對象的 mark0方法,可以將標記設置為當前位置。例如:

buf.position(32);
// Mark the current position 32
buf.mark();

在經過一系列修改位置的操作之后,可以通過調用從 Buffer 類繼承而來的 reset0方法,將緩沖區的位置重新設置為之前的標記:

//一系列buf 的操作
// Reset position to last marked 32
buf.reset();

3.6 翻轉flip

flip將limit設置為當前位置,然后將位置設置回0
flip 方法源代碼

 public final Buffer flip() {limit = position;position = 0;mark = -1;return this;}

flip 方法通常用于由寫模式轉換為讀模式即 完成寫操作后 需要讀取操作前調用flip

在這里插入圖片描述
上圖是完成寫操作,然后調用flip
limit = position;position = 0;
在這里插入圖片描述

3.7 清除clear

clear0方法將限制設置為容量,將位置設置為零,所以能夠將這些值存儲為之前創建緩沖區時
它們的狀態,但是這不會重新設置緩沖區中的數據,內容會保持不變。如果要重新設置數據,就必
須將新數據傳輸到緩沖區中。在想要重用緩沖區時通常需要調用 clear0方法
clear 源代碼

public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;}

在這里插入圖片描述
clear 之后
在這里插入圖片描述

3.8 壓縮compact

compact 將position到limit 之間的數據拷貝到從頭部(0開始-limit-position)
完成后 position=limit-position. limit=capacity

常用于 讀模式切換為寫模式
在這里插入圖片描述

3.9 rewind(倒回)

rewind0方法只是簡單地重新將位置設置為零,但不改變限制
rewind 源代碼

//Rewinds this buffer. The position is set to zero and the mark is discarded.
public final Buffer rewind() {position = 0;mark = -1;return this;}

3.10 寫數據

  • 調用 channel 的 read 方法
  • 調用 buffer 自己的 put 方法
//從channel 中讀取數據寫入buf,buf 的 position 會向后移動 readBytes  位
int readBytes = channel.read(buf);
//position 會向后移動1位
buf.put((byte)127);
方法描述
put(byte b)將參數指定的字節傳輸到緩沖區的當前位置并且將位置增加 1如果緩沖區的位置不比限制小,將會拋出BuferOverflowException 類型的異常
put(int index, byte b)將第二個參數指定的字節傳輸到緩沖區中由第一個參數指定的索引位置。緩沖區的位置不會改變。如果索引值為負,或者如果索引值大于或等于緩沖區的限制,將拋出IndexOutOfBoundsException 類型的異常
put(byte[] array)將 array 數組中的所有元素都傳輸到緩沖區中從當前位置開始的位置。位置被增加的值為數組的長度。如果緩沖區中沒有足夠的空間來存儲數組的內容,將會拋出BufferOverflowException 類型的異常
put(bytel] array, int offset, int length)從aray[offset]到array[offset+length-1](包括這兩個字節)的字節傳輸到緩沖區中從當前位置開始的位置,位置被增加的值為length。如果緩沖區中沒有足夠的空間來存儲它們,將會拋出BufferOverflowExcepiton類型的異常
put(ByteBuffer src)將src中保留的字節即src 中從當前索引位置到limit一1位置的元素傳輸到緩沖區中(從當前位置開始的位置,位置被增加的值為 src.remaining()),。如果存儲這些素的空間不夠,將會拋出BufficrOverflowException類型的異常。如果src與當前緩沖區一樣嘗試將級沖區傳輸到自身,將會拋出IlegalArgumentException 類型的異常

3.11 讀數據

  • 調用 channel 的 write 方法
  • 調用 buffer 自己的 get 方法
//從buf中讀取數據,寫入channel 中,position 會向后移動 writeBytes 位,注意寫后調取 buf.hasRemaining判斷是否buf 數據全部寫入channel 中(受channel 緩沖區的限制,不一定一次能把buf 中剩余的的數據全部寫入channel 中)
int writeBytes = channel.write(buf);
//position 會向后移動1位
byte b = buf.get();
方法描述
get()提取并返回當前緩沖區位置所在的字節并且增加位置的值
get(int index)返回索引位置index上的字節,position 不變
get(byte[]bytes)從緩沖區的位置0開始,往后提取 byteslength 個字節對緩沖區的位置值增加bytes.length,然后返回指向當前緩沖區的引用。如果緩沖區中可用的字節數少于bytes.length,將拋出 BufferUnderflowException 類型的異常
get(byte[] bytes,int offset, int length)從當前緩沖區位置開始,往后提取 length 個字節并且將它們存儲在 bytes 數組中從索引位置ofset開始的地方。緩沖區的位置值會增加 length,指向當前緩沖區的用會被返回。如果可用的字節數少于 length,將會拋出 BufferUnderflowException類型的異常;如果 ofset 和/或 length 的值導致一個非法的數組索引,將會拋出IndexOutOfBoundsException 類型的異常

4 常用使用方式

4.1 讀寫范式

  1. 向 buffer 寫入數據,例如調用 channel.read(buffer)
  2. 調用 flip() 切換至讀模式
  3. 從 buffer 讀取數據,例如調用 buffer.get()
  4. 調用 clear() 或 compact() 切換至寫模式
  5. 重復 1~4 步驟

4.2 與字符串之間的轉換

編碼:字符串調用getByte方法獲得byte數組,將byte數組放入ByteBuffer中
解碼:先調用ByteBuffer的flip方法,然后通過StandardCharsets的decoder方法解碼

public class Translate {public static void main(String[] args) {// 準備兩個字符串String str1 = "hello";// 方式1 通過字符串的getByte方法獲得字節數組,放入緩沖區中ByteBuffer buffer1 = ByteBuffer.allocate(16);buffer1.put(str1.getBytes());// 切換模式buffer1.flip();// 方式2 ByteBuffer buffer1 = ByteBuffer.wrap(str1.getBytes()); //此方式不用flip  因為wrap返回的buf position =0// 通過StandardCharsets解碼,獲得CharBuffer,再通過toString獲得字符串String  str2 = StandardCharsets.UTF_8.decode(buffer1).toString();System.out.println(str2);}
}

參見java7入門經典

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42966.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42966.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42966.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【mybatis】mapper.xml中foreach的用法,含批量查詢、插入、修改、刪除方法的使用

一、xml文件中foreach的主要屬性 foreach元素的屬性主要有 collection&#xff0c;item&#xff0c;index&#xff0c;separator&#xff0c;open&#xff0c;close。 collection: 表示集合&#xff0c;數據源 item &#xff1a;表示集合中的每一個元素 index &#xff1a;用于…

blender 發射體粒子

發射體粒子的基礎設置 選擇需要添加粒子的物體&#xff0c;點擊右側粒子屬性&#xff0c;在屬性面板中&#xff0c;點擊加號&#xff0c;物體表面會出現很多小點點&#xff0c;點擊空格鍵&#xff0c;粒子會自動運動&#xff0c;像下雨一樣&#xff1b; bender 粒子系統分為兩…

【100天精通python】Day40:GUI界面編程_PyQt 從入門到實戰(完)_網絡編程與打包發布

目錄 8 網絡編程 8.1 使用PyQt 網絡模塊進行網絡通信 服務器端示例 客戶端示例 8.2 處理網絡請求和響應 9 打包和發布 9.1 創建可執行文件或安裝程序 9.2 解決依賴問題 9.3 發布 PyQt 應用到不同平臺 9.3.1 發布到 Windows 9.3.2 發布到 macOS 9.3.3 發布到 Linux 9…

sap ui5刷新頁面的方式

1.第一種 window.location.reload();2.第二種 如果你想在UI5應用程序中使用MVC模式來處理頁面刷新,可以通過重新加載當前路由來實現刷新。首先,確保你有一個Router對象實例: var oRouter = sap.ui.core.UIComponent.getRouterFor(this);然后&

[保研/考研機試] KY43 全排列 北京大學復試上機題 C++實現

題目鏈接&#xff1a; 全排列https://www.nowcoder.com/share/jump/437195121692001512368 描述 給定一個由不同的小寫字母組成的字符串&#xff0c;輸出這個字符串的所有全排列。 我們假設對于小寫字母有a < b < ... < y < z&#xff0c;而且給定的字符串中的字…

Docker vs. Kubernetes:選擇合適的場景

在決定使用 Docker 還是 Kubernetes 之前&#xff0c;讓我們看看一些實際的場景&#xff0c;以便更好地理解它們的適用性。 使用 Docker 的場景 假設您正在開發一個微服務應用程序&#xff0c;其中每個微服務都需要一些特定的依賴項和環境。在這種情況下&#xff0c;Docker 是一…

HJ6 質數因子

描述 功能:輸入一個正整數&#xff0c;按照從小到大的順序輸出它的所有質因子&#xff08;重復的也要列舉&#xff09;&#xff08;如180的質因子為2 2 3 3 5 &#xff09; 數據范圍&#xff1a; 1≤n≤210914 1≤n≤210914 輸入描述&#xff1a; 輸入一個整數 輸出描述&…

學習Vue:聲明式路由和程序式路由

在Vue.js中&#xff0c;路由與導航是構建單頁應用程序&#xff08;SPA&#xff09;的關鍵概念。在使用Vue Router時&#xff0c;您可以使用兩種方式來進行路由與導航&#xff1a;聲明式路由和程序式導航。本文將詳細介紹這兩種方式&#xff0c;幫助您理解它們的用法和優勢。 聲…

Ceph入門到精通-Aws Iam(user,role,group,policy,resource)架構圖和快速入門

-- Aws Iam(identity,user,role,group,policy,resource,)架構圖和快速入門. 【官網】&#xff1a;Cloud Computing Services - Amazon Web Services (AWS) 應用場景 aws 云服務運維,devops過程中經常涉及各項服務&#xff0c;權限&#xff0c;角色的處理。 為了更好的使用各項…

Redis在Java中的基本使用

本片將介紹 Redis 在 Java 中的基本使用 文章目錄 1、使用jedis操作redis1.1、Jedis簡介1.2、引入jedis的Maven依賴1.2、獲取連接1.3、使用實例 2、對于JedisPooled的使用2.1、使用JedisPooled2.2、關于連接池 3、SpringBoot下使用Redis3.1、引入Maven依賴3.2、配置Redis連接3.…

mac m1上系統內錄內部聲音的方法/無需安裝Blackhole

總所周知&#xff0c;m1的mac不能錄制桌面音頻&#xff0c;obsstudio都不行。 最快的解決方法就是下載飛書&#xff1a; 登陸后新建直播/視頻會議&#xff1a; 共享的時候選擇下面的兩個鉤上去就好了

6.RocketMQ之索引文件ConsumeQueue

本文著重分析為consumequeue/topic/queueId目錄下的索引文件。 1.ConsumeQueueStore public class ConsumeQueueStore {protected final ConcurrentMap<String>, ConcurrentMap<Integer>, ConsumeQueueInterface>> consumeQueueTable;public boolean load(…

【BUG】docker安裝nacos,瀏覽器卻無法訪問到頁面

個人主頁&#xff1a;金鱗踏雨 個人簡介&#xff1a;大家好&#xff0c;我是金鱗&#xff0c;一個初出茅廬的Java小白 目前狀況&#xff1a;22屆普通本科畢業生&#xff0c;幾經波折了&#xff0c;現在任職于一家國內大型知名日化公司&#xff0c;從事Java開發工作 我的博客&am…

Socks5、IP代理在爬蟲開發與HTTP通信中的應用

隨著互聯網的不斷發展&#xff0c;代理服務器成為網絡工程師和數據爬蟲開發者的關鍵工具。本文將深入探討Socks5代理、IP代理以及它們在網絡安全、爬蟲開發和HTTP通信中的重要作用。 1. 代理服務器&#xff1a;保障隱私與安全的中間人 代理服務器是位于客戶端與目標服務器之間…

object獲取的兩種方式/Object.keys使用/解構賦值

object獲取的兩種方式&#xff1a; data() {return {abj: {aa: {A: 1}}}},created() {console.log(this.abj.aa) //第一種console.log(this.abj["aa"]) //第二種}, Object.keys使用/解構賦值&#xff1a; return {footList: [],abj: {aa: {A: 12,AA:22},bb: {…

軟件工程概述-架構師(三)

軟件工程概述&#xff08;老版&#xff09; 軟件開發生命周期&#xff1a; 軟件定義時期&#xff1a;包括 可行性研究和詳細需求分析過程&#xff0c;任務是軟件工程必需完成的目標&#xff0c;具有可行問題分析、可行性研究、需求分析等。軟件開發時期&#xff1a;軟件的 設…

20230818 數據庫自整理部分

并發事務 臟讀 一個事務讀取到另一事務還沒有提交的數據 事務B讀取了事務A還沒有提交的數據 不可重復讀 一個事務先后讀取同一條記錄&#xff0c;但是兩次讀取的數據不同&#xff0c;稱之為不可重復讀 查詢出來的數據不一樣 1步驟b還沒有提交 3步驟b已經提交 幻讀 一個…

SOLIDWORKS 2023中裝配體配合的正確使用方法 碩迪科技

-SOLIDWORKS 裝配體打開時是由不同的階段和性能檢查組成的。如果在創建裝配體時未應用基本的配合方法&#xff0c;問題會隨著時間的推移而累積&#xff0c;并且在使用時會出現明顯的速度減慢。 如果您的裝配體運行速度很慢&#xff0c;則很可能是在創建配合時出現了不良操作的癥…

C#如何遍歷類的屬性,并獲取描述/注釋

要獲取屬性的描述/注釋&#xff0c;需要使用System.ComponentModel命名空間中的DescriptionAttribute。可以通過反射獲取屬性上的DescriptionAttribute&#xff0c;并獲取其Description屬性值。 首先&#xff0c;需要引入System.ComponentModel命名空間&#xff1a; using Sy…

貝葉斯推理問題、MCMC和變分推理

一、說明 1.1 介紹 貝葉斯推理是統計學中的一個主要問題&#xff0c;在許多機器學習方法中也會遇到。例如&#xff0c;用于分類的高斯混合模型或用于主題建模的潛在狄利克雷分配都是在擬合數據時需要解決此類問題的圖形模型。 同時&#xff0c;可以注意到&#xff0c;貝葉斯推…