乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Java nio入門教程詳解(四)

       360lec 2016-09-30
      第二章 緩沖區(qū)
        我們以 Buffer類開始我們對java.nio軟件包的瀏覽歷程。這些類是java.nio的構(gòu)造基礎。在本章中,我們將深入研究緩沖區(qū),了解各種不同的類型,并學會怎樣使用。到那時我們將明了java.nio緩沖區(qū)是如何與java.nio.channels這一通道類相聯(lián)系的。
        一個Buffer對象是固定數(shù)量的數(shù)據(jù)的容器。其作用是一個存儲器,或者分段運輸區(qū),在這里數(shù)據(jù)可被存儲并在之后用于檢索。緩沖區(qū)如我們在第一章所討論的那樣被寫滿和釋放。對于每個非布爾原始數(shù)據(jù)類型都有一個緩沖區(qū)類。盡管緩沖區(qū)作用于它們存儲的原始數(shù)據(jù)類型,但緩沖區(qū)十分傾向于處理字節(jié)。非字節(jié)緩沖區(qū)可以在后臺執(zhí)行從字節(jié)或到字節(jié)的轉(zhuǎn)換,這取決于緩沖區(qū)是如何創(chuàng)建的。我們將在本章節(jié)后面的部分檢查緩沖區(qū)數(shù)據(jù)存儲的含義。
        緩沖區(qū)的工作與通道緊密聯(lián)系。通道是 I/O 傳輸發(fā)生時通過的入口,而緩沖區(qū)是這些數(shù)據(jù)傳輸?shù)膩碓椿蚰繕?。對于離開緩沖區(qū)的傳輸,您想傳遞出去的數(shù)據(jù)被置于一個緩沖區(qū),被傳送到通道。對于傳回緩沖區(qū)的傳輸,一個通道將數(shù)據(jù)放置在您所提供的緩沖區(qū)中。這種在協(xié)同對象(通常是您所寫的對象以及一到多個Channel對象之間進行的緩沖區(qū)數(shù)據(jù)傳遞是高效數(shù)據(jù)處理的關(guān)鍵。通道將在第三章被詳細涉及。
        圖 2-1 是 Buffer的類層次圖。在頂部是通用Buffer類(抽象父類)。Buffer定義所有緩沖區(qū)類型共有的操作,無論是它們所包含的數(shù)據(jù)類型還是可能具有的特定行為。這一共同點將會成為我們的出發(fā)點。
        
        圖 2-1. Buffer 類的家譜
        2.1 緩沖區(qū)基礎
        概念上,緩沖區(qū)是包在一個對象內(nèi)的基本數(shù)據(jù)元素數(shù)組。Buffer類相比一個簡單數(shù)組的優(yōu)點是它將關(guān)于數(shù)據(jù)的數(shù)據(jù)內(nèi)容和信息包含在一個單一的對象中。Buffer類以及它專有的子類定義了一個用于處理數(shù)據(jù)緩沖區(qū)的 API。
        2.1.1 屬性
        所有的緩沖區(qū)都具有四個屬性來提供關(guān)于其所包含的數(shù)據(jù)元素的信息。它們是:
        容量(Capacity)
        緩沖區(qū)能夠容納的數(shù)據(jù)元素的最大數(shù)量。這一容量在緩沖區(qū)創(chuàng)建時被設定,并且永遠不能被改變。
        上界(Limit)
        緩沖區(qū)的第一個不能被讀或?qū)懙脑?。或者說,緩沖區(qū)中現(xiàn)存元素的計數(shù)。
        位置(Position)
        下一個要被讀或?qū)懙脑氐乃饕N恢脮詣佑上鄳?get()和 put()函數(shù)更新。
        標記(Mark)
        一個備忘位置。調(diào)用 mark()來設定 mark = postion。調(diào)用 reset()設定 position = mark。標記在設定前是未定義的(undefined)。
        這四個屬性之間總是遵循以下關(guān)系:
        0 <= mark <= position <= limit <= capacity
        讓我們來看看這些屬性在實際應用中的一些例子。圖 2-2 展示了一個新創(chuàng)建的容量為10的 ByteBuffer邏輯視圖。
        
        圖 2-2. 新創(chuàng)建的 ByteBuffer
        位置被設為 0,而且容量和上界被設為 10,剛好經(jīng)過緩沖區(qū)能夠容納的最后一個字節(jié)。標記最初未定義。容量是固定的,但另外的三個屬性可以在使用緩沖區(qū)時改變。
        2.1.2 緩沖區(qū) API
        讓我們來看一下可以如何使用一個緩沖區(qū)。以下是 Buffer 類的方法簽名:
        package java.nio;
        public abstract class Buffer {
        public final int capacity();
        public final int position();
        public final Buffer position (int newPosition);
        public final int limit();
        public final Buffer limit (int newLimit);
        public final Buffer mark();
        public final Buffer reset();
        public final Buffer clear();
        public final Buffer flip();
        public final Buffer rewind();
        public final int remaining();
        public final boolean hasRemaining();
        public abstract boolean isReadOnly();
        }
        關(guān)于這個API有一點要注意的是,像clear()這類函數(shù),您通常應當返回void,而不是Buffer引用。這些函數(shù)將引用返回到它們在(this)上被引用的對象。這是一個允許級聯(lián)調(diào)用的類設計方法。級聯(lián)調(diào)用允許這種類型的代碼:
        buffer.mark();
        buffer.position(5);
        buffer.reset();
        被簡寫為:
        buffer.mark().position(5).reset();
        java.nio中的類被特意地設計為支持級聯(lián)調(diào)用。您可能已經(jīng)在StringBuffer類中看到了級聯(lián)調(diào)用的使用。;
        如果聰明地使用級聯(lián)調(diào)用,就能產(chǎn)生簡潔,優(yōu)美,易讀的代碼。但如果濫用,就會使代碼不知所云。當級聯(lián)調(diào)用可以增加可讀性并使讓您的目標更加明確時使用它。如果使用級聯(lián)調(diào)用會使代碼作用不夠清晰,那么請不要使用它。請時刻保證您的代碼易于他人閱讀。
        對于 API還要注意的一點是isReadOnly()函數(shù)。所有的緩沖區(qū)都是可讀的,但并非所有都可寫。每個具體的緩沖區(qū)類都通過執(zhí)行isReadOnly()來標示其是否允許該緩存區(qū)的內(nèi)容被修改。一些類型的緩沖區(qū)類可能未使其數(shù)據(jù)元素存儲在一個數(shù)組中 。例如MappedByteBuffer的內(nèi)容可能實際是一個只讀文件。您也可以明確地創(chuàng)建一個只讀視圖緩沖區(qū),來防止對內(nèi)容的意外修改。對只讀的緩沖區(qū)的修改嘗試將會導致ReadOnlyBufferException拋出。但是我們要提前做好準備。
        2.1.3 存取
        讓我們從起點開始。緩沖區(qū)管理著固定數(shù)目的數(shù)據(jù)元素。但在任何特定的時刻,我們可能只對緩沖區(qū)中的一部分元素感興趣。換句話說,在我們想清空緩沖區(qū)之前,我們可能只使用了緩沖區(qū)的一部分。這時,我們需要能夠追蹤添加到緩沖區(qū)內(nèi)的數(shù)據(jù)元素的數(shù)量,放入下一個元素的位置等等的方法。位置屬性做到了這一點。它在調(diào)用put()時指出了下一個數(shù)據(jù)元素應該被插入的位置,或者當get()被調(diào)用時指出下一個元素應從何處檢索。聰明的讀者會注意到上文所列出的的 Buffer API 并沒有包括get()或put()函數(shù)。每一個Buffer類都有這兩個函數(shù),但它們所采用的參數(shù)類型,以及它們返回的數(shù)據(jù)類型,對每個子類來說都是唯一的,所以它們不能在頂層Buffer類中被抽象地聲明。它們的定義必須被特定類型的子類所遵從。對于這一討論,我們將假設使用具有這里所給出的函數(shù)的 ByteBuffer類【get()和put()還有更多的形式,我們將在 2.1.10 小節(jié)中進行討論】:
        public abstract class ByteBuffer extends Buffer implements Comparable
        {
        // 這里是部分API列表
        public abstract byte get();
        public abstract byte get (int index);
        public abstract ByteBuffer put (byte b);
        public abstract ByteBuffer put (int index, byte b);
        }
        get和put可以是相對的或者是絕對的。在前面的程序列表中,相對方案是不帶有索引參數(shù)的函數(shù)。當相對函數(shù)被調(diào)用時,位置在返回時前進一。如果位置前進過多,相對運算就會拋出異常。對于put(),如果運算會導致位置超出上界 , 就會拋出BufferOverflowException異常。對于get(),如果位置不小于上界,就會拋出BufferUnderflowException異常。絕對存取不會影響緩沖區(qū)的位置屬性,但是如果您所提供的索引超出范圍(負數(shù)或不小于上界),也將拋出IndexOutOfBoundsException異常。
        2.1.4 填充
        讓我們看一個例子。我們將代表「Hello」字符串的 ASCII 碼載入一個名為 buffer 的ByteBuffer對象中。當在圖 2.2 所新建的緩沖區(qū)上執(zhí)行以下代碼后,緩沖區(qū)的結(jié)果狀態(tài)如圖 2.3 所示:
        buffer.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o');
        圖 2-3 五次調(diào)用 put()之后的緩沖區(qū)
        注意本例中的每個字符都必須被強制轉(zhuǎn)換為 byte。我們不能不經(jīng)強制轉(zhuǎn)換而這樣操作:
        buffer.put('H');
        因為我們存放的是字節(jié)而不是字符。記住在 java 中,字符在內(nèi)部以 Unicode 碼表示,每個 Unicode 字符占 16 位。本章節(jié)的例子使用包含 ascii 字符集數(shù)值的字節(jié)。通過將char 強制轉(zhuǎn)換為 byte,我們刪除了前八位來建立一個八位字節(jié)值。這通常只適合于拉丁字符而不能適合所有可能的 Unicode 字符。為了讓事情簡化,我們暫時故意忽略字符集的映射問題。第六章中將詳細涉及字符編碼。
        既然我們已經(jīng)在 buffer 中存放了一些數(shù)據(jù),如果我們想在不丟失位置的情況下進行一些更改該怎么辦呢?put()的絕對方案可以達到這樣的目的。假設我們想將緩沖區(qū)中的內(nèi)容從「Hello」的 ASCII 碼更改為「Mellow」。我們可以這樣實現(xiàn):
        buffer.put(0,(byte)'M').put((byte)'w');
        這里通過進行一次絕對方案的put將0位置的字節(jié)代替為十六進制數(shù)值0x4d,將0x77放入當前位置(當前位置不會受到絕對 put()的影響)的字節(jié),并將位置屬性加一。結(jié)果如圖 2.4 所示。
        
        圖 2-4 修改后的 buffer
        2.1.5 翻轉(zhuǎn)
        我們已經(jīng)寫滿了緩沖區(qū),現(xiàn)在我們必須準備將其清空。我們想把這個緩沖區(qū)傳遞給一個通道,以使內(nèi)容能被全部寫出。但如果通道現(xiàn)在在緩沖區(qū)上執(zhí)行g(shù)et(),那么它將從我們剛剛插入的有用數(shù)據(jù)之外取出未定義數(shù)據(jù)。如果我們將位置值重新設為 0,通道就會從正確位置開始獲取,但是它是怎樣知道何時到達我們所插入數(shù)據(jù)末端的呢?這就是上界屬性被引入的目的。上界屬性指明了緩沖區(qū)有效內(nèi)容的末端。我們需要將上界屬性設置為當前位置,然后將位置重置為 0。我們可以人工用下面的代碼實現(xiàn):
        buffer.limit(buffer.position()).position(0);
        但這種從填充到釋放狀態(tài)的緩沖區(qū)翻轉(zhuǎn)是 API 設計者預先設計好的,他們?yōu)槲覀兲峁┝艘粋€非常便利的函數(shù):
        Buffer.flip();
        flip()函數(shù)將一個能夠繼續(xù)添加數(shù)據(jù)元素的填充狀態(tài)的緩沖區(qū)翻轉(zhuǎn)成一個準備讀出元素的釋放狀態(tài)。在翻轉(zhuǎn)之后,圖 2.4 的緩沖區(qū)會變成圖 2.5 中的樣子。
        
        圖 2-5. 被翻轉(zhuǎn)后的緩沖區(qū)
        rewind()函數(shù)與flip()相似,但不影響上界屬性。它只是將位置值設回 0。您可以使用rewind()后退,重讀已經(jīng)被翻轉(zhuǎn)的緩沖區(qū)中的數(shù)據(jù)。
        如果將緩沖區(qū)翻轉(zhuǎn)兩次會怎樣呢?它實際上會大小變?yōu)?0。按照圖 2.5 的相同步驟對緩沖區(qū)進行操作;把上界設為位置的值,并把位置設為 0。上界和位置都變成 0。嘗試對緩沖區(qū)上位置和上界都為 0 的 get()操作會導致BufferUnderflowException異常。而 put()則會導致 BufferOverflowException 異常。
        2.1.6 釋放
        如果我們現(xiàn)在將圖 2.5 中的緩沖區(qū)傳入通道,它將取出我們存放在那里的數(shù)據(jù),從位置開始直到上界結(jié)束。很簡單,不是嗎?
        同樣地,如果您接收到一個在別處被填滿的緩沖區(qū),您可能需要在檢索內(nèi)容之前將其翻轉(zhuǎn)。例如,如果一個通道的read()操作完成,而您想要查看被通道放入緩沖區(qū)內(nèi)的數(shù)據(jù),那么您需要在調(diào)用get()之前翻轉(zhuǎn)緩沖區(qū)。通道對象在緩沖區(qū)上調(diào)用put()增加數(shù)據(jù);put()和read()可以隨意混合使用。
        布爾函數(shù)hasRemaining()會在釋放緩沖區(qū)時告訴您是否已經(jīng)達到緩沖區(qū)的上界。以下是一種將數(shù)據(jù)元素從緩沖區(qū)釋放到一個數(shù)組的方法(在 2.1.10 小節(jié)中,我們將學到進行批量傳輸?shù)母咝У姆椒?。
        for (int i = 0; buffer.hasRemaining(), i ) {
        myByteArray [i] = buffer.get();
        }
        作為選擇,remaining()函數(shù)將告知您從當前位置到上界還剩余的元素數(shù)目。您也可以通過下面的循環(huán)來釋放圖 2-5 所示的緩沖區(qū)。
        int count = buffer.remaining();
        for (int i = 0; i < count, i ) {
        myByteArray [i] = buffer.get();
        }
        如果您對緩沖區(qū)有專門的控制,這種方法會更高效,因為上界不會在每次循環(huán)重復時都被檢查(這要求調(diào)用一個buffer樣例程序)。上文中的第一個例子允許多線程同時從緩沖區(qū)釋放元素。
        緩沖區(qū)并不是多線程安全的。如果您想以多線程同時存取特定的緩沖區(qū),您需要在存取緩沖區(qū)之前進行同步(例如對緩沖區(qū)對象進行跟蹤)。
        一旦緩沖區(qū)對象完成填充并釋放,它就可以被重新使用了。clear()函數(shù)將緩沖區(qū)重置為空狀態(tài)。它并不改變緩沖區(qū)中的任何數(shù)據(jù)元素,而是僅僅將上界設為容量的值,并把位置設回 0,如圖 2.2 所示。這使得緩沖區(qū)可以被重新填入。參見示例 2.1。
        例 2.1 填充和釋放緩沖區(qū)
        package com.ronsoft.books.nio.buffers;
        import java.nio.CharBuffer;
        /**
        * Buffer fill/drain example. This code uses the simplest
        * means of filling and draining a buffer: one element at
        * a time.
        * @author Ron Hitchens (ron@ronsoft.com)
        */
        public class BufferFillDrain{
        public static void main (String [] argv) throws Exception{
        CharBuffer buffer = CharBuffer.allocate (100);
        while (fillBuffer(buffer)) {
        buffer.flip();
        drainBuffer(buffer);
        buffer.clear();
        }
        }
        private static void drainBuffer (CharBuffer buffer){
        while (buffer.hasRemaining()) {
        System.out.print (buffer.get());
        }
        System.out.println ("");
        }
        private static boolean fillBuffer (CharBuffer buffer){
        if (index >= strings.length) {
        return (false);
        }
        String string = strings [index ];
        for (int i = 0; i < string.length(); i ) {
        buffer.put (string.charAt (i));
        }
        return true;
        }
        private static int index = 0;
        private static String [] strings = {
        "A random string value",
        "The product of an infinite number of monkeys",
        "Hey hey we're the Monkees",
        "Opening act for the Monkees: Jimi Hendrix",
        "'Scuse me while I kiss this fly",
        "Help Me! Help Me!",
        };
        }
        2.1.7 壓縮
        public abstract class ByteBuffer extends Buffer implements Comparable
        {
        // 這里僅列出部分API
        public abstract ByteBuffer compact();
        }
        有時,您可能只想從緩沖區(qū)中釋放一部分數(shù)據(jù),而不是全部,然后重新填充。為了實現(xiàn)這一點,未讀的數(shù)據(jù)元素需要下移以使第一個元素索引為 0。盡管重復這樣做會效率低下,但這有時非常必要,而 API 對此為您提供了一個compact()函數(shù)。這一緩沖區(qū)工具在復制數(shù)據(jù)時要比您使用get()和put()函數(shù)高效得多。所以當您需要時,請使用compact()。圖 2.6顯示了一個我們已經(jīng)釋放了一些元素,并且現(xiàn)在我們想要對其進行壓縮的緩沖區(qū)。
        
        圖 2.6 被部分釋放的緩沖區(qū)
        這樣操作:
        buffer.compact();
        會導致緩沖區(qū)的狀態(tài)如圖 2-7 所示:
        
        圖 2.7 壓縮后的 buffer
        這里發(fā)生了幾件事。您會看到數(shù)據(jù)元素 2-5 被復制到 0-3 位置。位置 4 和 5 不受影響,但現(xiàn)在正在或已經(jīng)超出了當前位置,因此是「死的」。它們可以被之后的 put()調(diào)用重寫。還要注意的是,位置已經(jīng)被設為被復制的數(shù)據(jù)元素的數(shù)目。也就是說,緩沖區(qū)現(xiàn)在被定位在緩沖區(qū)中最后一個「存活」元素后插入數(shù)據(jù)的位置。最后,上界屬性被設置為容量的值,因此緩沖區(qū)可以被再次填滿。調(diào)用compact()的作用是丟棄已經(jīng)釋放的數(shù)據(jù),保留未釋放的數(shù)據(jù),并使緩沖區(qū)對重新填充容量準備就緒。您可以用這種類似于先入先出(FIFO)隊列的方式使用緩沖區(qū)。當然也存在更高效的算法(緩沖區(qū)移位并不是一個處理隊列的非常高效的方法)。但是壓縮對于使緩沖區(qū)與您從端口中讀入的數(shù)據(jù)(包)邏輯塊流的同步來說也許是一種便利的方法。
        如果您想在壓縮后釋放數(shù)據(jù),緩沖區(qū)會像之前所討論的那樣需要被翻轉(zhuǎn)。無論您之后是否要向緩沖區(qū)中添加新的數(shù)據(jù),這一點都是必要的。
        2.1.8 標記
        這本章節(jié)的開頭,我們已經(jīng)涉及了緩沖區(qū)四種屬性中的三種。第四種,標記,使緩沖區(qū)能夠記住一個位置并在之后將其返回。緩沖區(qū)的標記在mark()函數(shù)被調(diào)用之前是未定義的,調(diào)用時標記被設為當前位置的值。reset()函數(shù)將位置設為當前的標記值。如果標記值未定義,調(diào)用reset()將導致InvalidMarkException異常。一些緩沖區(qū)函數(shù)會拋棄已經(jīng)設定的標記(rewind(),clear(),以及 flip()總是拋棄標記)。如果新設定的值比當前的標記小,調(diào)用limit()或 position()帶有索引參數(shù)的版本會拋棄標記。
        注意不要混淆 reset()和 clear()。clear()函數(shù)將清空緩沖區(qū),而reset()位置返回到一個先前設定的標記。
        讓我們看看這是如何進行的。在圖 2.5 的緩沖區(qū)上執(zhí)行以下代碼將會導致圖 2-8 所顯示的緩沖區(qū)狀態(tài)。
        buffer.position(2).mark().position(4);
        圖 2-8 設有一個標記的緩沖區(qū)
        如果這個緩沖區(qū)現(xiàn)在被傳遞給一個通道,兩個字節(jié)(「ow」)將會被發(fā)送,而位置會前進到 6。如果我們此時調(diào)用reset(),位置將會被設為標記,如圖 2-9 所示。再次將緩沖區(qū)傳遞給通道將導致四個字節(jié)(「llow」)被發(fā)送。
        
        圖 2-9 一個緩沖區(qū)位置被重設為標記
        結(jié)果可能沒什么意義(owllow 會被寫入通道),但您了解了概念。
        2.1.9 比較
        有時候比較兩個緩沖區(qū)所包含的數(shù)據(jù)是很有必要的。所有的緩沖區(qū)都提供了一個常規(guī)的equals()函數(shù)用以測試兩個緩沖區(qū)的是否相等,以及一個compareTo()函數(shù)用以比較緩沖區(qū)。
        public abstract class ByteBuffer extends Buffer implements Comparable
        {
        // 這里僅列出部分API
        public boolean equals (Object ob);
        public int compareTo (Object ob);
        }
        兩個緩沖區(qū)可用下面的代碼來測試是否相等:
        if (buffer1.equals (buffer2)) {
        doSomething();
        }
        如果每個緩沖區(qū)中剩余的內(nèi)容相同,那么 equals()函數(shù)將返回true,否則返回false,因為這個測試是用于嚴格的相等而且是可換向的。前面的程序清單中的緩沖區(qū)名稱可以顛倒,并會產(chǎn)生相同的結(jié)果。兩個緩沖區(qū)被認為相等的充要條件是:
        兩個對象類型相同。包含不同數(shù)據(jù)類型的buffer永遠不會相等,而且buffer絕不會等于非buffer對象。
        兩個對象都剩余同樣數(shù)量的元素。Buffer的容量不需要相同,而且緩沖區(qū)中剩余數(shù)據(jù)的索引也不必相同。但每個緩沖區(qū)中剩余元素的數(shù)目(從位置到上界)必須相同。
        在每個緩沖區(qū)中應被get()函數(shù)返回的剩余數(shù)據(jù)元素序列必須一致。
        如果不滿足以上任意條件,就會返回 false。
        圖 2-10 說明了兩個屬性不同的緩沖區(qū)也可以相等。
        圖 2-11 顯示了兩個相似的緩沖區(qū),可能看起來是完全相同的緩沖區(qū),但測試時會發(fā)現(xiàn)并不相等。
        
        圖 2-10 兩個被認為是相等的緩沖區(qū)
        
        圖 2-11 兩個被認為不相等的緩沖區(qū)
        緩沖區(qū)也支持用compareTo()函數(shù)以詞典順序進行比較。這一函數(shù)在緩沖區(qū)參數(shù)小于,等于,或者大于引用compareTo()的對象實例時,分別返回一個負整數(shù),0 和正整數(shù)。這些就是所有典型的緩沖區(qū)所實現(xiàn)的java.lang.Comparable接口語義。這意味著緩沖區(qū)數(shù)組可以通過調(diào)用 java.util.Arrays.sort()函數(shù)按照它們的內(nèi)容進行排序。
        與equals()相似,compareTo()不允許不同對象間進行比較。但compareTo()更為嚴格:如果您傳遞一個類型錯誤的對象,它會拋出ClassCastException異常,但equals()只會返回false。
        比較是針對每個緩沖區(qū)內(nèi)剩余數(shù)據(jù)進行的,與它們在equals()中的方式相同,直到不相等的元素被發(fā)現(xiàn)或者到達緩沖區(qū)的上界。如果一個緩沖區(qū)在不相等元素發(fā)現(xiàn)前已經(jīng)被耗盡,較短的緩沖區(qū)被認為是小于較長的緩沖區(qū)。不像equals(),compareTo()不可交換:順序問題。在本例中,一個小于零的結(jié)果表明 buffer2小于buffer1,而表達式的值就會是true:
        if (buffer1.compareTo (buffer2) < 0) {
        doSomething();
        }
        如果前面的代碼被應用到圖 2-10 所示的緩沖區(qū)中,結(jié)果會是0,而 if 語句將毫無用處。被應用到圖 2-11 的緩沖區(qū)的相同測試將會返回一個正數(shù)(表明 buffer2大于buffer1),而這個表達式也會被判斷為 false。
        2.1.10 批量移動
        緩沖區(qū)的涉及目的就是為了能夠高效傳輸數(shù)據(jù)。一次移動一個數(shù)據(jù)元素,如例 2-1 所示的那樣并不高效。如您在下面的程序清單中所看到的那樣,buffer API 提供了向緩沖區(qū)內(nèi)外批量移動數(shù)據(jù)元素的函數(shù)。
        public abstract class CharBuffer extends Buffer implements CharSequence, Comparable
        {
        // This is a partial API listing
        public CharBuffer get (char [] dst)
        public CharBuffer get (char [] dst, int offset, int length)
        public final CharBuffer put (char[] src)
        public CharBuffer put (char [] src, int offset, int length)
        public CharBuffer put (CharBuffer src)
        public final CharBuffer put (String src)
        public CharBuffer put (String src, int start, int end)
        }
        有兩種形式的 get()可供從緩沖區(qū)到數(shù)組進行的數(shù)據(jù)復制使用。第一種形式只將一個數(shù)組作為參數(shù),將一個緩沖區(qū)釋放到給定的數(shù)組。第二種形式使用 offset 和 length 參數(shù)來指定目標數(shù)組的子區(qū)間。這些批量移動的合成效果與前文所討論的循環(huán)是相同的,但是這些方法可能高效得多,因為這種緩沖區(qū)實現(xiàn)能夠利用本地代碼或其他的優(yōu)化來移動數(shù)據(jù)。批量移動總是具有指定的長度。也就是說,您總是要求移動固定數(shù)量的數(shù)據(jù)元素。當參看程序簽名時這一點還不明顯,但是對get()的這一引用:
        buffer.get(myArray);
        等價于:
        buffer.get(myArray,0,myArray.length);
        如果您所要求的數(shù)量的數(shù)據(jù)不能被傳送,那么不會有數(shù)據(jù)被傳遞,緩沖區(qū)的狀態(tài)保持不變,同時拋出BufferUnderflowException異常。因此當您傳入一個數(shù)組并且沒有指定長
        度,您就相當于要求整個數(shù)組被填充。如果緩沖區(qū)中的數(shù)據(jù)不夠完全填滿數(shù)組,您會得到一個異常。這意味著如果您想將一個小型緩沖區(qū)傳入一個大型數(shù)組,您需要明確地指定緩沖區(qū)中剩余的數(shù)據(jù)長度。上面的第一個例子不會如您第一眼所推出的結(jié)論那樣,將緩沖區(qū)內(nèi)剩余的數(shù)據(jù)元素復制到數(shù)組的底部。要將一個緩沖區(qū)釋放到一個大數(shù)組中,要這樣做:
        char [] bigArray = new char [1000];
        // Get count of chars remaining in the buffer
        int length = buffer.remaining();
        // Buffer is known to contain < 1,000 chars
        buffer.get (bigArrray, 0, length);
        // Do something useful with the data
        processData (bigArray, length);
        記住在調(diào)用get()之前必須查詢緩沖區(qū)中的元素數(shù)量(因為我們需要告知processData()被放置在bigArray中的字符個數(shù))。調(diào)用get()會向前移動緩沖區(qū)的位置屬性,所以之后調(diào)用remaining()會返回 0。get()的批量版本返回緩沖區(qū)的引用,而不是被傳送的數(shù)據(jù)元素的計數(shù),以減輕級聯(lián)調(diào)用的困難。另一方面,如果緩沖區(qū)存有比數(shù)組能容納的數(shù)量更多的數(shù)據(jù),您可以重復利用如下文所示的程序塊進行讀?。?div>  char [] smallArray = new char [10];
        while (buffer.hasRemaining()) {
        int length = Math.min (buffer.remaining(), smallArray.length);
        buffer.get (smallArray, 0, length);
        processData (smallArray, length);
        }
        put()的批量版本工作方式相似,但以相反的方向移動數(shù)據(jù),從數(shù)組移動到緩沖區(qū)。他們在傳送數(shù)據(jù)的大小方面有著相同的語義:
        buffer.put(myArray);
        等價于:
        buffer.put(myArray,0,myArray.length);
        批量傳輸?shù)拇笮】偸枪潭ǖ?。省略長度意味著整個數(shù)組會被填滿。
        如果緩沖區(qū)有足夠的空間接受數(shù)組中的數(shù)據(jù)(buffer.remaining()>myArray.length),數(shù)據(jù)將會被復制到從當前位置開始的緩沖區(qū),并且緩沖區(qū)位置會被提前所增加數(shù)據(jù)元素的數(shù)量。如果緩沖區(qū)中沒有足夠的空間,那么不會有數(shù)據(jù)被傳遞,同時拋出一個BufferOverflowException異常。
        也可以通過調(diào)用帶有一個緩沖區(qū)引用作為參數(shù)的put()來在兩個緩沖區(qū)內(nèi)進行批量傳遞。
        buffer.put(srcBuffer);
        這等價于(假設 dstBuffer 有足夠的空間):
        while (srcBuffer.hasRemaining()) {
        dstBuffer.put (srcBuffer.get());
        }
        兩個緩沖區(qū)的位置都會前進所傳遞的數(shù)據(jù)元素的數(shù)量。范圍檢查會像對數(shù)組一樣進行。具體來說,如果srcBuffer.remaining()大于 dstBuffer.remaining(),那么數(shù)據(jù)不會被傳遞,同時拋出BufferOverflowException異常。如果您對將一個緩沖區(qū)傳遞給它自己,就會引發(fā) java.lang.IllegalArgumentException 異常。
        在這一章節(jié)中我一直使用 CharBuffer 為例,而且到目前為止,這一討論也已經(jīng)應用到了其他的典型緩沖區(qū)上,比如 FloatBuffer,LongBuffer,等等。但是在下面的 API 程序清單的最后兩個函數(shù)中包含了兩個只對CharBuffer適用的批量移動函數(shù)。
        public abstract class CharBuffer extends Buffer implements CharSequence, Comparable
        {
        // 這里僅列出部分API
        public final CharBuffer put (String src)
        public CharBuffer put (String src, int start, int end)
        }
        這些函數(shù)使用 String 作為參數(shù),而且與作用于 char 數(shù)組的批量移動函數(shù)相似。如所有的 java 程序員所知,String 不同于 char 數(shù)組。但 String 確實包含 char 字符串,而且我們?nèi)祟惔_實傾向于將其在概念上認為是 char 數(shù)組(尤其是我們中曾經(jīng)是或者現(xiàn)在還是 C 或C 程序員的那些人)。由于這些原因,CharBuffer 類提供了將 String 復制到CharBuffer 中的便利方法。
        String 移動與 char 數(shù)組移動相似,除了在序列上是由 start 和 end 1 下標確定(與String.subString()類似),而不是 start 下標和 length。所以:
        buffer.put(myString);
        等價于:
        buffer.put(myString,0,myString.length);
        而這就是您怎樣復制字符 5-8,總共四個字符,從 myString 復制到 buffer。
        buffer.put(myString,5,9);
        String 批量移動等效于下面的代碼:
        for (int i = start; i < end; i ) {
        buffer.put (myString.charAt (i));
        }
        對String要進行與char數(shù)組相同的范圍檢查。如果所有的字符都不適合緩沖區(qū),將會拋出BufferOverflowException異常。
        Java nio入門教程詳解(五)

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多