<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 1.簡介 Java NIO 相關類在 JDK 1.4 中被引入,用于提高 I/O 的效率。Java NIO 包含了很多東西,但核心的東西不外乎 Buffer、Channel 和 Selector。本文中,我們先來聊聊的 Buffer 的實現。Channel 和 Selector 將在隨后的文章中講到。 ## [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#2繼承體系)2.繼承體系 Buffer 的繼承類比較多,用于存儲各種類型的數據。包括 ByteBuffer、CharBuffer、IntBuffer、FloatBuffer 等等。這其中,ByteBuffer 最為常用。所以接下來將會主要分析 ByteBuffer 的實現。Buffer 的繼承體系圖如下: ![](https://blog-pictures.oss-cn-shanghai.aliyuncs.com/15200845921379.jpg) ## [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#3屬性及相關操作)3.屬性及相關操作 Buffer 本質就是一個數組,只不過在數組的基礎上進行適當的封裝,方便使用。 Buffer 中有幾個重要的屬性,通過這幾個屬性來顯示數據存儲的信息。這個屬性分別是: | 屬性 | 說明 | | --- | --- | | capacity?容量 | Buffer 所能容納數據元素的最大數量,也就是底層數組的容量值。在創建時被指定,不可更改。 | | position 位置 | 下一個被讀或被寫的位置 | | limit 上界 | 可供讀寫的最大位置,用于限制?position,position < limit | | mark 標記 | 位置標記,用于記錄某一次的讀寫位置,可以通過 reset 重新回到這個位置 | ### [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#31-bytebuffer-初始化)3.1 ByteBuffer 初始化 ByteBuffer 可通過 allocate、allocateDirect 和 wrap 等方法初始化,這里以 allocate 為例: ``` public static ByteBuffer allocate(int capacity) { if (capacity &lt; 0) throw new IllegalArgumentException(); return new HeapByteBuffer(capacity, capacity); } HeapByteBuffer(int cap, int lim) { super(-1, 0, lim, cap, new byte[cap], 0); } ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset) { super(mark, pos, lim, cap); this.hb = hb; this.offset = offset; } ``` 上面是 allocate 創建 ByteBuffer 的過程,ByteBuffer 是抽象類,所以實際上創建的是其子類 HeapByteBuffer。HeapByteBuffer 在構造方法里調用父類構造方法,將一些參數值傳遞給父類。最后父類再做一次中轉,相關參數最終被傳送到 Buffer 的構造方法中了。我們再來看一下 Buffer 的源碼: ``` public abstract class Buffer { // Invariants: mark &lt;= position &lt;= limit &lt;= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; Buffer(int mark, int pos, int lim, int cap) { // package-private if (cap &lt; 0) throw new IllegalArgumentException("Negative capacity: " + cap); this.capacity = cap; limit(lim); position(pos); if (mark &gt;= 0) { if (mark &gt; pos) throw new IllegalArgumentException("mark &gt; position: (" + mark + " &gt; " + pos + ")"); this.mark = mark; } } } ``` Buffer 創建完成后,底層數組的結構信息如下: ![](https://blog-pictures.oss-cn-shanghai.aliyuncs.com/15200935482408.jpg) 上面的幾個屬性作為公共屬性,被放在了 Buffer 中,相關的操作方法也是封裝在 Buffer 中。那么接下來,我們來看看這些方法吧。 ### [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#32-bytebuffer-讀寫操作)3.2 ByteBuffer 讀寫操作 ByteBuffer 讀寫操作時通過 get 和 put 完成的,這兩個方法都有重載,我們只看其中一個。 ``` // 讀操作 public byte get() { return hb[ix(nextGetIndex())]; } final int nextGetIndex() { if (position &gt;= limit) throw new BufferUnderflowException(); return position++; } // 寫操作 public ByteBuffer put(byte x) { hb[ix(nextPutIndex())] = x; return this; } final int nextPutIndex() { if (position &gt;= limit) throw new BufferOverflowException(); return position++; } ``` 讀寫操作都會修改 position 的值,每次讀寫的位置是當前 position 的下一個位置。通過修改 position,我們可以讀取指定位置的數據。當然,前提是 position < limit。Buffer 中提供了`position(int)`方法用于修改 position 的值。 ``` public final Buffer position(int newPosition) { if ((newPosition &gt; limit) || (newPosition &lt; 0)) throw new IllegalArgumentException(); position = newPosition; if (mark &gt; position) mark = -1; return this; } ``` 當我們向一個剛初始化好的 Buffer 中寫入一些數據時,數據存儲示意圖如下: ![](https://blog-pictures.oss-cn-shanghai.aliyuncs.com/15201321822256.jpg) 如果我們想讀取剛剛寫入的數據,就需要修改 position 的值。否則 position 將指向沒有存儲數據的空間上,讀取空白空間是沒意義的。如上圖,我們可以將 position 設置為 0,這樣就能從頭讀取剛剛寫入的數據。 ![](https://blog-pictures.oss-cn-shanghai.aliyuncs.com/15201324263318.jpg) 僅修改 position 的值是不夠的,如果想正確讀取剛剛寫入的數據,還需修改 limit 的值,不然還是會讀取到空白空間上的內容。我們將 limit 指向數據區域的尾部,即可避免這個問題。修改 limit 的值通過 limit(int) 方法進行。 ``` public final Buffer limit(int newLimit) { if ((newLimit &gt; capacity) || (newLimit &lt; 0)) throw new IllegalArgumentException(); limit = newLimit; if (position &gt; limit) position = limit; if (mark &gt; limit) mark = -1; return this; } ``` 修改后,數據存儲示意圖如下: ![](https://blog-pictures.oss-cn-shanghai.aliyuncs.com/15201327069487.jpg) 上面為了正確讀取寫入的數據,需要兩步操作。Buffer 中提供了一個便利的方法,將這兩步操作合二為一,即 flip 方法。 ``` public final Buffer flip() { // 1. 設置 limit 為當前位置 limit = position; // 1. 設置 position 為0 position = 0; mark = -1; return this; } ``` ### [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#33-bytebuffer-標記)3.3 ByteBuffer 標記 我們在讀取或寫入的過程中,可以在感興趣的位置打上一個標記,這樣我們可以通過這個標記再次回到這個位置。Buffer 中,打標記的方法是 mark,回到標記位置的方法時 reset。簡單看下源碼吧。 ``` public final Buffer mark() { mark = position; return this; } public final Buffer reset() { int m = mark; if (m &lt; 0) throw new InvalidMarkException(); position = m; return this; } ``` 打標記及回到標記位置的流程如下: ![](https://blog-pictures.oss-cn-shanghai.aliyuncs.com/15201350084493.jpg) ## [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#4directbytebuffer)4.DirectByteBuffer 在 ByteBuffer 初始化一節中,我介紹了 ByteBuffer 的 allocate 方法,該方法實際上創建的是 HeapByteBuffer 對象。除了 allocate 方法,ByteBuffer 還有一個方法 allocateDirect。這個方法創建的是 DirectByteBuffer 對象。兩者有什么區別呢?簡單的說,allocate 方法所請求的空間是在 JVM 堆內進行分配的,而 allocateDirect 請求的空間則是在 JVM 堆外的,這部分空間不被 JVM 所管理。那么堆內空間和堆空間在使用上有什么不同呢?用一個表格列舉一下吧。 | 空間類型 | 優點 | 缺點 | | --- | --- | --- | | 堆內空間 | 分配速度快 | JVM 整理內存空間時,堆內空間的位置會被搬動,比較笨重 | | 堆外空間 | 1\. 空間位置固定,不用擔心空間被 JVM 隨意搬動 2\. 降低堆內空間的使用率 | 1\. 分配速度慢 2\. 回收策略比較復雜 | DirectByteBuffer 牽涉的底層技術點比較多,想要弄懂,還需要好好打基礎才行。由于本人目前能力很有限,關于 DirectByteBuffer 只能簡單講講。待后續能力提高時,我會再來重寫這部分的內容。如果想了解這方面的內容,建議大家看看其他的文章。 ## [](http://www.tianxiaobo.com/2018/03/04/Java-NIO%E4%B9%8B%E7%BC%93%E5%86%B2%E5%8C%BA/#5總結)5.總結 Buffer 是 Java NIO 中一個重要的輔助類,使用比較頻繁。在不熟悉 Buffer 的情況下,有時候很容易因為忘記調用 flip 或其他方法導致程序出錯。不過好在 Buffer 的源碼不難理解,大家可以自己看看,這樣可以避免出現一些奇怪的錯誤。 好了,本文到這里就結束了,謝謝閱讀!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看