官术网_书友最值得收藏!

1.3 Buffer類(lèi)的使用

在JDK 1.8.0_92版本中,Buffer類(lèi)的API列表如圖1-7所示。

圖1-7 Buffer類(lèi)的API列表

本節(jié)會(huì)對(duì)這些API進(jìn)行演示和講解,目的就是讓讀者全面地掌握NIO核心類(lèi)—Buffer的使用。

需要注意的是,Buffer.java類(lèi)是抽象類(lèi),并不能直接實(shí)例化,而其子類(lèi):ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer也是抽象類(lèi)。這7個(gè)子類(lèi)的聲明信息如下:

public abstract class ByteBuffer extends Buffer
public abstract class CharBuffer extends Buffer
public abstract class DoubleBuffer extends Buffer
public abstract class FloatBuffer extends Buffer
public abstract class IntBuffer extends Buffer
public abstract class LongBuffer extends Buffer
public abstract class ShortBuffer extends Buffer

抽象類(lèi)Buffer.java的7個(gè)子類(lèi)也是抽象類(lèi),也就意味著B(niǎo)yteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer這些類(lèi)也不能被直接new實(shí)例化。如果不能直接new實(shí)例化,那么如何創(chuàng)建這些類(lèi)的對(duì)象呢?使用的方式是將上面7種數(shù)據(jù)類(lèi)型的數(shù)組包裝(wrap)進(jìn)緩沖區(qū)中,此時(shí)就需要借助靜態(tài)方法wrap()進(jìn)行實(shí)現(xiàn)。wrap()方法的作用是將數(shù)組放入緩沖區(qū)中,來(lái)構(gòu)建存儲(chǔ)不同數(shù)據(jù)類(lèi)型的緩沖區(qū)。

注意

緩沖區(qū)為非線(xiàn)程安全的。

下面就要開(kāi)始介紹Buffer類(lèi)中全部的API了。雖然Buffer類(lèi)的7個(gè)子類(lèi)都有與其父類(lèi)(Buffer類(lèi))相同的API,但為了演示代碼的簡(jiǎn)短性,在測(cè)試中只使用ByteBuffer或CharBuffer類(lèi)作為API功能的演示。

1.3.1 包裝數(shù)據(jù)與獲得容量

在NIO技術(shù)的緩沖區(qū)中,存在4個(gè)核心技術(shù)點(diǎn),分別是:

?capacity(容量)

?limit(限制)

?position(位置)

?mark(標(biāo)記)

這4個(gè)技術(shù)點(diǎn)之間值的大小關(guān)系如下:

0≤mark≤position≤limit≤capacity

首先介紹一下緩沖區(qū)的capacity,它代表包含元素的數(shù)量。緩沖區(qū)的capacity不能為負(fù)數(shù),并且capacity也不能更改。

int capacity()方法的作用:返回此緩沖區(qū)的容量。

示例代碼如下:

        public class Test1 {
        public static void main(String[] args) {
            byte[] byteArray = new byte[] { 1, 2, 3 };
            short[] shortArray = new short[] { 1, 2, 3, 4 };
            int[] intArray = new int[] { 1, 2, 3, 4, 5 };
            long[] longArray = new long[] { 1, 2, 3, 4, 5, 6 };
            float[] floatArray = new float[] { 1, 2, 3, 4, 5, 6, 7 };
            double[] doubleArray = new double[] { 1, 2, 3, 4, 5, 6, 7, 8 };
            char[] charArray = new char[] { 'a', 'b', 'c', 'd' };
            ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
            ShortBuffer shortBuffer = ShortBuffer.wrap(shortArray);
            IntBuffer intBuffer = IntBuffer.wrap(intArray);
            LongBuffer longBuffer = LongBuffer.wrap(longArray);
            FloatBuffer floatBuffer = FloatBuffer.wrap(floatArray);
            DoubleBuffer doubleBuffer = DoubleBuffer.wrap(doubleArray);
            CharBuffer charBuffer = CharBuffer.wrap(charArray);
            System.out.println("bytebuffer=" + bytebuffer.getClass().getName());
            System.out.println("shortBuffer=" + shortBuffer.getClass().getName());
            System.out.println("intBuffer=" + intBuffer.getClass().getName());
            System.out.println("longBuffer=" + longBuffer.getClass().getName());
            System.out.println("floatBuffer=" + floatBuffer.getClass().getName());
            System.out.println("doubleBuffer=" + doubleBuffer.getClass().getName());
            System.out.println("charBuffer=" + charBuffer.getClass().getName());
            System.out.println();
            System.out.println("bytebuffer.capacity=" + bytebuffer.capacity());
            System.out.println("shortBuffer.capacity=" + shortBuffer.capacity());
            System.out.println("intBuffer.capacity=" + intBuffer.capacity());
            System.out.println("longBuffer.capacity=" + longBuffer.capacity());
            System.out.println("floatBuffer.capacity=" + floatBuffer.capacity());
            System.out.println("doubleBuffer.capacity=" + doubleBuffer.capacity());
            System.out.println("charBuffer.capacity=" + charBuffer.capacity());
        }
        }

程序運(yùn)行結(jié)果如下:

bytebuffer=java.nio.HeapByteBuffer
shortBuffer=java.nio.HeapShortBuffer
intBuffer=java.nio.HeapIntBuffer
longBuffer=java.nio.HeapLongBuffer
floatBuffer=java.nio.HeapFloatBuffer
doubleBuffer=java.nio.HeapDoubleBuffer
charBuffer=java.nio.HeapCharBuffer
bytebuffer.capacity=3
shortBuffer.capacity=4
intBuffer.capacity=5
longBuffer.capacity=6
floatBuffer.capacity=7
doubleBuffer.capacity=8
charBuffer.capacity=4

由于ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer是抽象類(lèi),因此wrap()就相當(dāng)于創(chuàng)建這些緩沖區(qū)的工廠方法,在源代碼中創(chuàng)建的流程示例如圖1-8所示。

圖1-8 創(chuàng)建流程

從源代碼中可以發(fā)現(xiàn),通過(guò)創(chuàng)建HeapByteBuffer類(lèi)的實(shí)例來(lái)實(shí)現(xiàn)創(chuàng)建ByteBuffer類(lèi)的實(shí)例。因?yàn)锽yteBuffer與HeapByteBuffer是父子類(lèi)的關(guān)系,所以在將HeapByteBuffer類(lèi)的對(duì)象賦值給數(shù)據(jù)類(lèi)型為ByteBuffer的變量時(shí)產(chǎn)生多態(tài)關(guān)系。

ByteBuffer類(lèi)緩沖區(qū)的技術(shù)原理就是使用byte[]數(shù)組進(jìn)行數(shù)據(jù)的保存,在后續(xù)使用指定的API來(lái)操作這個(gè)數(shù)組以達(dá)到操作緩沖區(qū)的目的,示例代碼如圖1-9所示。

圖1-9 HeapByteBuffer類(lèi)構(gòu)造方法的流程

在HeapByteBuffer類(lèi)的構(gòu)造方法中,使用代碼super(-1, off, off + len, buf.length, buf, 0)調(diào)用父類(lèi)的構(gòu)造方法將字節(jié)數(shù)組buf傳給父類(lèi)ByteBuffer,而且子類(lèi)HeapByteBuffer還重寫(xiě)了父類(lèi)ByteBuffer中的大部分方法,因此,在調(diào)用HeapByteBuffer類(lèi)的API時(shí),訪(fǎng)問(wèn)的是父類(lèi)中的buf字節(jié)數(shù)組變量,在調(diào)用API處理buf字節(jié)數(shù)組中的數(shù)據(jù)時(shí),執(zhí)行的是HeapByteBuffer類(lèi)中重寫(xiě)的方法。

從源代碼中可以了解到,緩沖區(qū)存儲(chǔ)的數(shù)據(jù)還是存儲(chǔ)在byte[]字節(jié)數(shù)組中。使用緩沖區(qū)與使用byte[]字節(jié)數(shù)組的優(yōu)點(diǎn)在于緩沖區(qū)將存儲(chǔ)數(shù)據(jù)的byte[]字節(jié)數(shù)組內(nèi)容與相關(guān)的信息整合在1個(gè)Buffer類(lèi)中,將數(shù)據(jù)與緩沖區(qū)中的信息進(jìn)行了整合,并進(jìn)行了封裝,這樣便于獲得相關(guān)的信息及處理數(shù)據(jù)。

capacity代表著緩沖區(qū)的大小,效果如圖1-10所示。

圖1-10 容量圖示

緩沖區(qū)中的capacity其實(shí)就是buf.length屬性值。

1.3.2 限制獲取與設(shè)置

方法int limit()的作用:返回此緩沖區(qū)的限制。

方法Buffer limit(int newLimit)的作用:設(shè)置此緩沖區(qū)的限制。

什么是限制呢?緩沖區(qū)中的限制代表第一個(gè)不應(yīng)該讀取或?qū)懭朐氐膇ndex(索引)。緩沖區(qū)的限制(limit)不能為負(fù),并且limit不能大于其capacity。如果position大于新的limit,則將position設(shè)置為新的limit。如果mark已定義且大于新的limit,則丟棄該mark。

position和mark這兩個(gè)知識(shí)點(diǎn)在后面的章節(jié)有詳細(xì)的介紹,此處只需要理解“限制(limit)代表第一個(gè)不應(yīng)該讀取或?qū)懭朐氐膇ndex,緩沖區(qū)的limit不能為負(fù),并且limit不能大于其capacity”即可。

limit的應(yīng)用示例如圖1-11所示。

圖1-11 limit應(yīng)用示例

雖然圖1-11中的緩沖區(qū)一共有11個(gè)位置可以存放數(shù)據(jù),但只允許前4個(gè)位置存放數(shù)據(jù),后面的其他位置不可以存放數(shù)據(jù)。因此,JDK API DOC中對(duì)limit的解釋是:代表第一個(gè)不應(yīng)該讀取或?qū)懭朐氐膇ndex。下面再用代碼進(jìn)行驗(yàn)證,測(cè)試源代碼如下:

public class Test2 {
public static void main(String[] args) {
    char[] charArray = new char[] { 'a', 'b', 'c', 'd', 'e' };
    CharBuffer buffer = CharBuffer.wrap(charArray);
    System.out.println("A capacity()=" + buffer.capacity() + " limit()=" +
        buffer.limit());
    buffer.limit(3);
    System.out.println();
    System.out.println("B capacity()=" + buffer.capacity() + " limit()=" +
        buffer.limit());
    buffer.put(0, 'o'); //0
    buffer.put(1, 'p'); //1
    buffer.put(2, 'q'); //2
    buffer.put(3, 'r'); //3--此位置是第一個(gè)不可讀不可寫(xiě)的索引
    buffer.put(4, 's'); //4
    buffer.put(5, 't'); //5
    buffer.put(6, 'u'); //6
}
}

程序運(yùn)行后,在第16行出現(xiàn)異常,如圖1-12所示。

圖1-12 出現(xiàn)異常

在A處打印的值是兩個(gè)5,說(shuō)明在調(diào)用wrap()方法后,limit的值是capacity+1,因?yàn)閘imit取值范圍是從索引0開(kāi)始,而capacity是從1開(kāi)始。

Limit使用的場(chǎng)景就是當(dāng)反復(fù)地向緩沖區(qū)中存取數(shù)據(jù)時(shí)使用,比如第1次向緩沖區(qū)中存儲(chǔ)9個(gè)數(shù)據(jù),分別是A、B、C、D、E、F、G、H、I,如圖1-13所示。

圖1-13 第1次存儲(chǔ)9個(gè)數(shù)據(jù)

然后讀取全部9個(gè)數(shù)據(jù),完成后再進(jìn)行第2次向緩沖區(qū)中存儲(chǔ)數(shù)據(jù),第2次只存儲(chǔ)4個(gè)數(shù)據(jù),分別是1、2、3、4,效果如圖1-14所示。

圖1-14 第2次存儲(chǔ)4個(gè)數(shù)據(jù)

當(dāng)讀取時(shí)卻出現(xiàn)了問(wèn)題,如果讀取全部數(shù)據(jù)1、2、3、4、E、F、G、H、I時(shí)是錯(cuò)誤的,所以要結(jié)合limit來(lái)限制讀取的范圍,在E處設(shè)置limit,從而實(shí)現(xiàn)只能讀取1、2、3、4這4個(gè)正確的數(shù)據(jù)。

1.3.3 位置獲取與設(shè)置

方法int position()的作用:返回此緩沖區(qū)的位置。

方法Buffer position(int newPosition)的作用:設(shè)置此緩沖區(qū)新的位置。

什么是位置呢?它代表“下一個(gè)”要讀取或?qū)懭朐氐膇ndex(索引),緩沖區(qū)的position(位置)不能為負(fù),并且position不能大于其limit。如果mark已定義且大于新的position,則丟棄該mark。

position應(yīng)用示例如圖1-15所示。

圖1-15 position應(yīng)用示例

在圖1-13中,position對(duì)應(yīng)的index是3,說(shuō)明從此位置處開(kāi)始寫(xiě)入或讀取,直到limit結(jié)束。

下面用代碼來(lái)驗(yàn)證position是下一個(gè)讀取或?qū)懭氩僮鞯膇ndex:

public class Test3 {
public static void main(String[] args) {
    char[] charArray = new char[] { 'a', 'b', 'c', 'd' };
    CharBuffer charBuffer = CharBuffer.wrap(charArray);
    System.out.println("A capacity()=" + charBuffer.capacity() + " limit()=" +
        charBuffer.limit() + " position()="
            + charBuffer.position());
    charBuffer.position(2);
    System.out.println("B capacity()=" + charBuffer.capacity() + " limit()=" +
        charBuffer.limit() + " position()="
            + charBuffer.position());
    charBuffer.put("z");
    for (int i = 0; i < charArray.length; i++) {
        System.out.print(charArray[i] + " ");
    }
}
}

程序運(yùn)行結(jié)果如下:

A capacity()=4 limit()=4 position()=0
B capacity()=4 limit()=4 position()=2
a b z d

1.3.4 剩余空間大小獲取

方法int remaining()的作用:返回“當(dāng)前位置”與limit之間的元素?cái)?shù)。

方法remaining()的應(yīng)用示例如圖1-16所示。

圖1-16 方法remaining()應(yīng)用示例

方法int remaining()的內(nèi)部源代碼如下:

public final int remaining() {
    return limit - position;
}

示例代碼如下:

public class Test4 {
public static void main(String[] args) {
    char[] charArray = new char[] { 'a', 'b', 'c', 'd', 'e' };
    CharBuffer charBuffer = CharBuffer.wrap(charArray);
    System.out.println("A capacity()=" + charBuffer.capacity() + " limit()=" +
        charBuffer.limit() + " position()="
            + charBuffer.position());
    charBuffer.position(2);
    System.out.println("B capacity()=" + charBuffer.capacity() + " limit()=" +
        charBuffer.limit() + " position()="
            + charBuffer.position());
    System.out.println("C remaining()=" + charBuffer.remaining());
}
}

程序運(yùn)行結(jié)果如下:

A capacity()=5 limit()=5 position()=0
B capacity()=5 limit()=5 position()=2
C remaining()=3

1.3.5 使用Buffer mark()方法處理標(biāo)記

方法Buffer mark()的作用:在此緩沖區(qū)的位置設(shè)置標(biāo)記。

標(biāo)記有什么作用呢?緩沖區(qū)的標(biāo)記是一個(gè)索引,在調(diào)用reset()方法時(shí),會(huì)將緩沖區(qū)的position位置重置為該索引。標(biāo)記(mark)并不是必需的。定義mark時(shí),不能將其定義為負(fù)數(shù),并且不能讓它大于position。如果定義了mark,則在將position或limit調(diào)整為小于該mark的值時(shí),該mark被丟棄,丟棄后mark的值是-1。如果未定義mark,那么調(diào)用reset()方法將導(dǎo)致拋出InvalidMarkException異常。

緩沖區(qū)中的mark有些類(lèi)似于探險(xiǎn)或爬山時(shí)在關(guān)鍵路口設(shè)置“路標(biāo)”,目的是在原路返回時(shí)找到回去的路。

mark的示例代碼如下:

public class Test5 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    System.out.println("bytebuffer.capacity=" + bytebuffer.capacity());
    System.out.println();
    bytebuffer.position(1);
    bytebuffer.mark();   //在位置1設(shè)置mark
    System.out.println("bytebuffer.position=" + bytebuffer.position());
    bytebuffer.position(2);      //改變位置
    bytebuffer.reset();  //位置重置
    System.out.println();
    // 回到位置為1處
    System.out.println("bytebuffer.position=" + bytebuffer.position());
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer.capacity=3
bytebuffer.position=1
bytebuffer.position=1

1.3.6 知識(shí)點(diǎn)細(xì)化測(cè)試

前面介紹了緩沖區(qū)4個(gè)核心技術(shù)點(diǎn):capacity、limit、position和mark,根據(jù)這4個(gè)技術(shù)點(diǎn),可以設(shè)計(jì)出以下7個(gè)實(shí)驗(yàn)。

1)緩沖區(qū)的capacity不能為負(fù)數(shù),緩沖區(qū)的limit不能為負(fù)數(shù),緩沖區(qū)的position不能為負(fù)數(shù)。

2)position不能大于其limit。

3)limit不能大于其capacity。

4)如果定義了mark,則在將position或limit調(diào)整為小于該mark的值時(shí),該mark被丟棄。

5)如果未定義mark,那么調(diào)用reset()方法將導(dǎo)致拋出InvalidMarkException異常。

6)如果position大于新的limit,則position的值就是新limit的值。

7)當(dāng)limit和position值一樣時(shí),在指定的position寫(xiě)入數(shù)據(jù)時(shí)會(huì)出現(xiàn)異常,因?yàn)榇宋恢檬潜幌拗频摹?/p>

1.驗(yàn)證第1條

驗(yàn)證:緩沖區(qū)的capacity不能為負(fù)數(shù),緩沖區(qū)的limit不能為負(fù)數(shù),緩沖區(qū)的position不能為負(fù)數(shù)。

首先測(cè)試一下“緩沖區(qū)的capacity不能為負(fù)數(shù)”,需要使用allocate()方法開(kāi)辟出指定空間大小的緩沖區(qū),示例代碼如下:

public class Test1_1 {
public static void main(String[] args) {
    try {
        ByteBuffer bytebuffer = ByteBuffer.allocate(-1);
    } catch (IllegalArgumentException e) {
        System.out.println("ByteBuffer容量capacity大小不能為負(fù)數(shù)");
    }
}
}

allocate(int capacity)方法分配一個(gè)新的緩沖區(qū)。

程序運(yùn)行結(jié)果如下:

ByteBuffer容量capacity大小不能為負(fù)數(shù)

然后測(cè)試一下“緩沖區(qū)的limit不能為負(fù)數(shù)”,示例代碼如下:

public class Test1_2 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    try {
        bytebuffer = (ByteBuffer) bytebuffer.limit(-1);
    } catch (IllegalArgumentException e) {
        System.out.println("ByteBuffer限制limit大小不能為負(fù)數(shù)");
    }
}
}

程序運(yùn)行結(jié)果如下:

ByteBuffer限制limit大小不能為負(fù)數(shù)

最后測(cè)試一下“緩沖區(qū)的position不能為負(fù)數(shù)”,示例代碼如下:

public class Test1_3 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    try {
        bytebuffer = (ByteBuffer) bytebuffer.position(-1);
    } catch (IllegalArgumentException e) {
        System.out.println("ByteBuffer位置position大小不能為負(fù)數(shù)");
    }
}
}

程序運(yùn)行結(jié)果如下:

ByteBuffer位置position大小不能為負(fù)數(shù)

2.驗(yàn)證第2條

驗(yàn)證:position不能大于其limit。

示例代碼如下:

public class Test2 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    bytebuffer.limit(2);
    try {
        bytebuffer.position(3);
    } catch (IllegalArgumentException e) {
        System.out.println("ByteBuffer的position位置不能大于其limit限制");
    }
}
}

程序運(yùn)行結(jié)果如下:

ByteBuffer的position位置不能大于其limit限制

3.驗(yàn)證第3條

驗(yàn)證:limit不能大于其capacity。

示例代碼如下:

public class Test3 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    try {
        bytebuffer.limit(100);
    } catch (IllegalArgumentException e) {
        System.out.println("ByteBuffer的limit不能大于其capacity容量");
    }
}
}

程序運(yùn)行結(jié)果如下:

ByteBuffer的limit不能大于其capacity容量

4.驗(yàn)證第4條

驗(yàn)證:如果定義了mark,則在將position或limit調(diào)整為小于該mark的值時(shí),該mark被丟棄。

在此處將第4條拆分成4點(diǎn)來(lái)分別進(jìn)行驗(yàn)證。

1)如果定義了mark,則在將position調(diào)整為不小于該mark的值時(shí),該mark不丟棄。

2)如果定義了mark,則在將position調(diào)整為小于該mark的值時(shí),該mark被丟棄。

3)如果定義了mark,則在將limit調(diào)整為不小于該mark的值時(shí),該mark不丟棄。

4)如果定義了mark,則在將limit調(diào)整為小于該mark的值時(shí),該mark被丟棄。

首先驗(yàn)證一下“如果定義了mark,則在將position調(diào)整為不小于該mark的值時(shí),該mark不丟棄”,示例代碼如下:

public class Test4_1 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    bytebuffer.position(1);
    bytebuffer.mark();
    System.out.println("bytebuffer在 " + bytebuffer.position() + " 位置設(shè)置mark標(biāo)記");
    bytebuffer.position(2);
    bytebuffer.reset();
    System.out.println();
    System.out.println("bytebuffer回到" + bytebuffer.position() + "位置");
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer在1位置設(shè)置mark標(biāo)記
bytebuffer回到1位置

然后驗(yàn)證一下“如果定義了mark,則在將position調(diào)整為小于該mark的值時(shí),該mark將被丟棄”,示例代碼如下:

public class Test4_2 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    bytebuffer.position(2);
    bytebuffer.mark();
    bytebuffer.position(1);
    try {
        bytebuffer.reset();
    } catch (InvalidMarkException e) {
        System.out.println("bytebuffer的mark標(biāo)記無(wú)效");
    }
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer的mark標(biāo)記無(wú)效

接著驗(yàn)證一下“如果定義了mark,則在將limit調(diào)整為不小于該mark的值時(shí),該mark不丟棄”,示例代碼如下:

public class Test4_3 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
    System.out.println("A byteBuffer position=" + byteBuffer.position() +
        " limit=" + byteBuffer.limit());
    System.out.println();
    byteBuffer.position(2);
    byteBuffer.mark();
    System.out.println("B byteBuffer position=" + byteBuffer.position() +
        " limit=" + byteBuffer.limit());
    byteBuffer.position(3);
    byteBuffer.limit(3);
    System.out.println();
    System.out.println("C byteBuffer position=" + byteBuffer.position() +
        " limit=" + byteBuffer.limit());
    byteBuffer.reset();
    System.out.println();
    System.out.println("D byteBuffer position=" + byteBuffer.position() +
        " limit=" + byteBuffer.limit());
}
}

程序運(yùn)行結(jié)果如下:

A byteBuffer position=0 limit=3
B byteBuffer position=2 limit=3
C byteBuffer position=3 limit=3
D byteBuffer position=2 limit=3

最后驗(yàn)證一下“如果定義了mark,則在將limit調(diào)整為小于該mark的值時(shí),該mark被丟棄”,示例代碼如下:

public class Test4_4 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
    System.out.println("A byteBuffer position=" + byteBuffer.position() +" limit=" + byteBuffer.limit());
    System.out.println();
    byteBuffer.position(2);
    byteBuffer.mark();
    System.out.println("B byteBuffer position=" + byteBuffer.position() +
        " limit=" + byteBuffer.limit());
    byteBuffer.limit(1);
    System.out.println();
    System.out.println("C byteBuffer position=" + byteBuffer.position() +
        " limit=" + byteBuffer.limit());
    System.out.println();
    try {
        byteBuffer.reset();
    } catch (InvalidMarkException e) {
        System.out.println("byteBuffer mark丟失");
    }
}
}

程序運(yùn)行結(jié)果如下:

A byteBuffer position=0 limit=3
B byteBuffer position=2 limit=3
C byteBuffer position=1 limit=1
byteBuffer mark丟失

總結(jié):limit和position不能小于mark,如果小于則mark丟棄。

5.驗(yàn)證第5條

驗(yàn)證:如果未定義mark,那么調(diào)用reset()方法將導(dǎo)致拋出InvalidMarkException異常。示例代碼如下:

public class Test5 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    try {
        bytebuffer.reset();
    } catch (InvalidMarkException e) {
        System.out.println("bytebuffer的mark標(biāo)記無(wú)效");
    }
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer的mark標(biāo)記無(wú)效

6.驗(yàn)證第6條

驗(yàn)證:如果position大于新的limit,則position的值就是新limit的值。

示例代碼如下:

public class Test6 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    bytebuffer.position(3);
    System.out.println("bytebuffer limit(2)之前的位置:" + bytebuffer.position());
    bytebuffer.limit(2);
    System.out.println();
    System.out.println("bytebuffer limit(2)之后的位置:" + bytebuffer.position());
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer limit(2)之前的位置:3
bytebuffer limit(2)之后的位置:2

7.驗(yàn)證第7條

驗(yàn)證:當(dāng)limit和position值一樣時(shí),在指定的position寫(xiě)入數(shù)據(jù)時(shí)會(huì)出現(xiàn)異常,因?yàn)榇宋恢檬潜幌拗频摹?/p>

示例代碼如下:

public class Test7 {
public static void main(String[] args) {
    char[] charArray = new char[] { 'a', 'b', 'c', 'd' };
    CharBuffer charBuffer = CharBuffer.wrap(charArray);
    System.out.println("A capacity()=" + charBuffer.capacity() + " limit()=" +
        charBuffer.limit() + " position()="
            + charBuffer.position());
    System.out.println();
    charBuffer.position(1);
    charBuffer.limit(1);
    charBuffer.put("z");
}
}

程序運(yùn)行結(jié)果如下:

A capacity()=4 limit()=4 position()=0
Exception in thread "main" java.nio.BufferOverflowException
    at java.nio.CharBuffer.put(CharBuffer.java:922)
    at java.nio.CharBuffer.put(CharBuffer.java:950)
    at BufferAPITest.Details.Test7.main(Test7.java:15)

1.3.7 判斷只讀

boolean isReadOnly()方法的作用:告知此緩沖區(qū)是否為只讀緩沖區(qū)。

示例代碼如下:

public class Test6 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    short[] shortArray = new short[] { 1, 2, 3, 4 };
    int[] intArray = new int[] { 1, 2, 3, 4, 5 };
    long[] longArray = new long[] { 1, 2, 3, 4, 5, 6 };
    float[] floatArray = new float[] { 1, 2, 3, 4, 5, 6, 7 };
    double[] doubleArray = new double[] { 1, 2, 3, 4, 5, 6, 7, 8 };
    char[] charArray = new char[] { 'a', 'b', 'c', 'd' };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    ShortBuffer shortBuffer = ShortBuffer.wrap(shortArray);
    IntBuffer intBuffer = IntBuffer.wrap(intArray);
    LongBuffer longBuffer = LongBuffer.wrap(longArray);
    FloatBuffer floatBuffer = FloatBuffer.wrap(floatArray);
    DoubleBuffer doubleBuffer = DoubleBuffer.wrap(doubleArray);
    CharBuffer charBuffer = CharBuffer.wrap(charArray);
    System.out.println("bytebuffer.isReadOnly=" + bytebuffer.isReadOnly());
    System.out.println("shortBuffer.isReadOnly=" + shortBuffer.isReadOnly());
    System.out.println("intBuffer.isReadOnly=" + intBuffer.isReadOnly());
    System.out.println("longBuffer.isReadOnly=" + longBuffer.isReadOnly());
    System.out.println("floatBuffer.isReadOnly=" + floatBuffer.isReadOnly());
    System.out.println("doubleBuffer.isReadOnly=" + doubleBuffer.isReadOnly());
    System.out.println("charBuffer.isReadOnly=" + charBuffer.isReadOnly());
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer.isReadOnly=false
shortBuffer.isReadOnly=false
intBuffer.isReadOnly=false
longBuffer.isReadOnly=false
floatBuffer.isReadOnly=false
doubleBuffer.isReadOnly=false
charBuffer.isReadOnly=false

1.3.8 直接緩沖區(qū)

boolean isDirect()方法的作用:判斷此緩沖區(qū)是否為直接緩沖區(qū)。那什么是“直接緩沖區(qū)”呢?先來(lái)看看使用非直接緩沖區(qū)操作數(shù)據(jù)的流程,如圖1-17所示。

圖1-17 使用非直接緩沖區(qū)保存數(shù)據(jù)的過(guò)程

在圖1-17中可以發(fā)現(xiàn),通過(guò)ByteBuffer向硬盤(pán)存取數(shù)據(jù)時(shí)是需要將數(shù)據(jù)暫存在JVM的中間緩沖區(qū),如果有頻繁操作數(shù)據(jù)的情況發(fā)生,則在每次操作時(shí)都會(huì)將數(shù)據(jù)暫存在JVM的中間緩沖區(qū),再交給ByteBuffer處理,這樣做就大大降低軟件對(duì)數(shù)據(jù)的吞吐量,提高內(nèi)存占有率,造成軟件運(yùn)行效率降低,這就是非直接緩沖區(qū)保存數(shù)據(jù)的過(guò)程,所以非直接緩沖區(qū)的這個(gè)弊端就由直接緩沖區(qū)解決了。

使用直接緩沖區(qū)操作數(shù)據(jù)的過(guò)程如圖1-18所示。

圖1-18 使用直接緩沖區(qū)保存數(shù)據(jù)的過(guò)程

如果使用直接緩沖區(qū)來(lái)實(shí)現(xiàn)兩端數(shù)據(jù)交互,則直接在內(nèi)核空間中就進(jìn)行了處理,無(wú)須JVM創(chuàng)建新的緩沖區(qū),這樣就減少了在JVM中創(chuàng)建中間緩沖區(qū)的步驟,增加了程序運(yùn)行效率。

示例代碼如下:

public class Test7_1 {
public static void main(String[] args) {
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(100);
    System.out.println(byteBuffer.isDirect());
}
}

打印結(jié)果如下:

true

成功創(chuàng)建出直接緩沖區(qū)。

1.3.9 還原緩沖區(qū)的狀態(tài)

final Buffer clear()方法的作用:還原緩沖區(qū)到初始的狀態(tài),包含將位置設(shè)置為0,將限制設(shè)置為容量,并丟棄標(biāo)記,即“一切為默認(rèn)”。

clear()方法的內(nèi)部源代碼如下:

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

clear()方法的主要使用場(chǎng)景是在對(duì)緩沖區(qū)存儲(chǔ)數(shù)據(jù)之前調(diào)用此方法。例如:

buf.clear();       //準(zhǔn)備開(kāi)始向緩沖區(qū)中寫(xiě)數(shù)據(jù)了,緩沖區(qū)的狀態(tài)要通過(guò)clear()進(jìn)行還原
in.read(buf);     //從in開(kāi)始讀數(shù)據(jù),將數(shù)據(jù)寫(xiě)入buf中

需要注意的是,clear()方法“不能真正清除”緩沖區(qū)中的數(shù)據(jù),雖然從名稱(chēng)來(lái)看它似乎能夠這樣做,這樣命名是因?yàn)樗诙鄶?shù)情況下確實(shí)有清除數(shù)據(jù)的作用,那么怎么“清除”數(shù)據(jù)呢?例如,調(diào)用代碼“buf.clear(); ”后將緩沖區(qū)的狀態(tài)進(jìn)行還原,包含將position(位置)歸0,再執(zhí)行寫(xiě)入新數(shù)據(jù)的代碼,將最新版的數(shù)據(jù)由索引位置0開(kāi)始覆蓋,這樣就將緩沖區(qū)中的舊值用新值覆蓋了,相當(dāng)于數(shù)據(jù)被清除了。

示例代碼如下:

public class Test8 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    bytebuffer.position(2);
    bytebuffer.limit(3);
    bytebuffer.mark();
    bytebuffer.clear();
    System.out.println("bytebuffer.position=" + bytebuffer.position());
    System.out.println();
    System.out.println("bytebuffer.limit=" + bytebuffer.limit());
    System.out.println();
    try {
        bytebuffer.reset();
    } catch (java.nio.InvalidMarkException e) {
    }
        System.out.println("bytebuffer mark丟失");
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer.position=0
bytebuffer.limit=3
bytebuffer mark丟失

1.3.10 對(duì)緩沖區(qū)進(jìn)行反轉(zhuǎn)

final Buffer flip()方法的作用:反轉(zhuǎn)此緩沖區(qū)。首先將限制設(shè)置為當(dāng)前位置,然后將位置設(shè)置為0。如果已定義了標(biāo)記,則丟棄該標(biāo)記。

flip()方法的通俗解釋是“縮小limit的范圍,類(lèi)似于String.subString(0, endIndex)方法”。

flip()方法的內(nèi)部源代碼如下:

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

當(dāng)向緩沖區(qū)中存儲(chǔ)數(shù)據(jù),然后再?gòu)木彌_區(qū)中讀取這些數(shù)據(jù)時(shí),就是使用flip()方法的最佳時(shí)機(jī),示例代碼如下:

A—buf.allocate(10);

B—buf.put(8);

C—首先向buf寫(xiě)入數(shù)據(jù),此步驟是重點(diǎn)操作;

D—buf.flip();

E—然后從buf讀出數(shù)據(jù),此步驟是重點(diǎn)操作。

當(dāng)執(zhí)行A處代碼時(shí),緩沖區(qū)出現(xiàn)10個(gè)空的位置,索引形式如下:

0   1   2   3   4   5   6   7   8   9

當(dāng)執(zhí)行B處代碼時(shí),position為0的位置存入數(shù)字8,然后position自動(dòng)變成1,因?yàn)閜ut()方法會(huì)將position進(jìn)行自增,這時(shí)緩沖區(qū)中的數(shù)據(jù)如下:

0   1   2   3   4   5   6   7   8   9
8

當(dāng)執(zhí)行C處代碼時(shí),假設(shè)要寫(xiě)入的數(shù)據(jù)數(shù)組為{11, 22, 33, 44, 55},將這5個(gè)數(shù)字在position是1的位置依次存入buf中,完成后的緩沖區(qū)中的數(shù)據(jù)如下:

0   1    2    3    4    5    6    7    8    9
8   11   22   33   44   55

這時(shí)position的值是6,下一步要將緩沖區(qū)中的數(shù)據(jù)讀取出來(lái)時(shí),有效的數(shù)據(jù)應(yīng)該是:

8 11 22 33 44 55

因?yàn)槲恢?~7~8~9中存儲(chǔ)的值是無(wú)效的,所以調(diào)用D處代碼flip()后將position的值6作為limit的值,而position被重新賦值為0,有效數(shù)據(jù)的范圍為:

0   1    2    3    4    5
8   11   22   33   44   55

最后執(zhí)行E處代碼,將這些有效的數(shù)據(jù)讀取出來(lái)。

final Buffer flip()方法常用在向緩沖區(qū)中寫(xiě)入一些數(shù)據(jù)后,下一步讀取緩沖區(qū)中的數(shù)據(jù)之前,以改變limit與position的值。

方法flip會(huì)改變position和limit的值,示例代碼如下:

public class Test11 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    bytebuffer.position(2);
    bytebuffer.mark();
    bytebuffer.flip();
    System.out.println("bytebuffer.position=" + bytebuffer.position());
    System.out.println();
    System.out.println("bytebuffer.limit=" + bytebuffer.limit());
    System.out.println();
    try {
        bytebuffer.reset();
    } catch (java.nio.InvalidMarkException e) {
        System.out.println("bytebuffer mark丟失");
    }
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer.position=0
bytebuffer.limit=2
bytebuffer mark丟失

final Buffer flip()方法常用在向緩沖區(qū)中寫(xiě)入一些數(shù)據(jù)后,下一步讀取緩沖區(qū)中的數(shù)據(jù)之前調(diào)用,以改變limit與position的值,示例代碼如下:

public class Test11_1 {
public static void main(String[] args) {
    CharBuffer charBuffer = CharBuffer.allocate(20);
    System.out.println("A position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 一共寫(xiě)入14個(gè)字
    charBuffer.put("我是中國(guó)人我在中華人民共和國(guó)");
    System.out.println("B position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    charBuffer.position(0); // 位置position還原成0
    System.out.println("C position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 下面for語(yǔ)句的打印效果是“國(guó)”字后面有6個(gè)空格,這6個(gè)空格是無(wú)效的數(shù)據(jù)
    // 應(yīng)該只打印前14個(gè)字符,后6個(gè)字符不再讀取
    for (int i = 0; i < charBuffer.limit(); i++) {
        System.out.print(charBuffer.get());
    }
    System.out.println();
    // 上面的代碼是錯(cuò)誤讀取數(shù)據(jù)的代碼
    // 下面的代碼是正確讀取數(shù)據(jù)的代碼
    System.out.println("D position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 還原緩沖區(qū)的狀態(tài)
    charBuffer.clear();
    System.out.println("E position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 繼續(xù)寫(xiě)入
    charBuffer.put("我是美國(guó)人");
    System.out.println("F position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 設(shè)置for循環(huán)結(jié)束的位置,也就是新的limit值
    charBuffer.limit(charBuffer.position());
    charBuffer.position(0);
    System.out.println("G position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    for (int i = 0; i < charBuffer.limit(); i++) {
        System.out.print(charBuffer.get());
    }
}
}

程序運(yùn)行結(jié)果如下:

A position=0 limit=20
B position=14 limit=20
C position=0 limit=20
我是中國(guó)人我在中華人民共和國(guó)空格空格空格空格空格空格
D position=20 limit=20
E position=0 limit=20
F position=5 limit=20
G position=0 limit=5
我是美國(guó)人

上面的程序在讀取數(shù)據(jù)時(shí)都要執(zhí)行以下代碼:

charBuffer.limit(charBuffer.position());
charBuffer.position(0);

這樣會(huì)顯得比較煩瑣,可以使用flip()方法,示例代碼如下:

public class Test11_2 {
public static void main(String[] args) {
    CharBuffer charBuffer = CharBuffer.allocate(20);
    System.out.println("A position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 一共寫(xiě)入14個(gè)字
    charBuffer.put("我是中國(guó)人我在中華人民共和國(guó)");
    System.out.println("B position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    charBuffer.position(0); // 位置position還原成0
    System.out.println("C position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 下面for語(yǔ)句的打印效果是“國(guó)”字后面有6個(gè)空格,這6個(gè)空格是無(wú)效的數(shù)據(jù)
    // 應(yīng)該只打印前14個(gè)字符,后6個(gè)字符不再讀取
    for (int i = 0; i < charBuffer.limit(); i++) {
        System.out.print(charBuffer.get());
    }
    System.out.println();
    // 上面的代碼是錯(cuò)誤讀取數(shù)據(jù)的代碼
    // 下面的代碼是正確讀取數(shù)據(jù)的代碼
    System.out.println("D position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 還原緩沖區(qū)的狀態(tài)
    charBuffer.clear();
    System.out.println("E position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 繼續(xù)寫(xiě)入
    charBuffer.put("我是美國(guó)人");
    System.out.println("F position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    // 使用flip()方法
    charBuffer.flip();
    System.out.println("G position=" + charBuffer.position() + " limit=" +
        charBuffer.limit());
    for (int i = 0; i < charBuffer.limit(); i++) {
        System.out.print(charBuffer.get());
    }
}
}

得出的運(yùn)行結(jié)果是一樣的。

1.3.11 判斷是否有底層實(shí)現(xiàn)的數(shù)組

final boolean hasArray()方法的作用:判斷此緩沖區(qū)是否具有可訪(fǎng)問(wèn)的底層實(shí)現(xiàn)數(shù)組。該方法的內(nèi)部源代碼如下:

public final boolean hasArray() {
    return (hb ! = null) && ! isReadOnly;
}

示例代碼如下:

public class Test12 {
public static void main(String[] args) throws IOException {
    ByteBuffer byteBuffer = ByteBuffer.allocate(100);
    byteBuffer.put((byte) 1);
    byteBuffer.put((byte) 2);
    System.out.println(byteBuffer.hasArray());
}
}

程序運(yùn)行結(jié)果如下:

true

也可以對(duì)直接緩沖區(qū)進(jìn)行判斷,示例代碼如下:

public class Test12_1 {
public static void main(String[] args) throws IOException {
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(100);
    byteBuffer.put((byte) 1);
    byteBuffer.put((byte) 2);
    System.out.println(byteBuffer.hasArray());
}
}

程序運(yùn)行結(jié)果如下:

false

打印true值是因?yàn)樵谠创a:

public abstract class ByteBuffer
    extends Buffer
    implements Comparable<ByteBuffer>
{
    final byte[] hb;

程序中使用byte[] hb存儲(chǔ)數(shù)據(jù),所以hb[]對(duì)象為非空,結(jié)果就是true。

打印false代表byte[] hb數(shù)組值為null,并沒(méi)有將數(shù)據(jù)存儲(chǔ)到hb[]中,而是直接存儲(chǔ)在內(nèi)存中。

hasArray()方法的內(nèi)部源代碼

public final boolean hasArray() {
    return (hb ! = null) && ! isReadOnly;
}

正是以byte[] hb是否有值來(lái)判斷是否有底層數(shù)組支持。

1.3.12 判斷當(dāng)前位置與限制之間是否有剩余元素

final boolean hasRemaining()方法的作用:判斷在當(dāng)前位置和限制之間是否有元素。該方法的內(nèi)部源代碼如下:

public final boolean hasRemaining() {
    return position < limit;
}

final int remaining()方法的作用:返回“當(dāng)前位置”與限制之間的元素個(gè)數(shù)。該方法的內(nèi)部源代碼如下:

public final int remaining() {
    return limit - position;
}

示例代碼如下:

public class Test13 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    
    bytebuffer.limit(3);
    bytebuffer.position(2);
    System.out.println("bytebuffer.hasRemaining=" + bytebuffer.hasRemaining() +
         " bytebuffer.remaining="
              + bytebuffer.remaining());
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer.hasRemaining=true bytebuffer.remaining=1

這兩個(gè)方法可以在讀寫(xiě)緩沖區(qū)中的數(shù)據(jù)時(shí)使用。本例僅測(cè)試讀數(shù)據(jù)時(shí)的使用情況,示例代碼如下:

public class Test13_1 {
public static void main(String[] args) {
    byte[] byteArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
    int remaining = byteBuffer.remaining();
    for (int i = 0; i < remaining; i++) {
        System.out.print(byteBuffer.get() + " ");
    }
    System.out.println();
    byteBuffer.clear();
    while (byteBuffer.hasRemaining()) {
        System.out.print(byteBuffer.get() + " ");
    }
    System.out.println();
    byteBuffer.clear();
    for (; byteBuffer.hasRemaining() == true; ) {
        System.out.print(byteBuffer.get() + " ");
    }
}
}

程序運(yùn)行結(jié)果如下:

1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9

運(yùn)行結(jié)果表明成功取出全部的數(shù)據(jù)。

1.3.13 重繞緩沖區(qū)

final Buffer rewind()方法的作用:重繞此緩沖區(qū),將位置設(shè)置為0并丟棄標(biāo)記。該方法

的內(nèi)部源代碼如下。

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

在一系列通道“重新寫(xiě)入或獲取”的操作之前調(diào)用此方法(假定已經(jīng)適當(dāng)設(shè)置了限制)。例如:

out.write(buf);   //將buf的remaining剩余空間的數(shù)據(jù)輸出到out中
buf.rewind();     //rewind重繞緩沖區(qū)
buf.get(array);   //從緩沖區(qū)獲取數(shù)據(jù)保存到array中

rewind()方法的通俗解釋就是“標(biāo)記清除,位置position值歸0, limit不變”。

rewind()方法沒(méi)有設(shè)置限制,說(shuō)明此方法可以結(jié)合自定義的limit限制值。

注意:rewind()方法常在重新讀取緩沖區(qū)中數(shù)據(jù)時(shí)使用。

final Buffer clear()方法的作用:清除此緩沖區(qū),將位置設(shè)置為0,將限制設(shè)置為容量,并丟棄標(biāo)記,方法內(nèi)部的源代碼如下。

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

方法clear()的主要使用場(chǎng)景是在對(duì)緩沖區(qū)進(jìn)行存儲(chǔ)數(shù)據(jù)之前調(diào)用此方法。例如:

buf.clear();    //Prepare buffer for reading
in.read(buf);  //Read data

此方法不能實(shí)際清除緩沖區(qū)中的數(shù)據(jù),但從名稱(chēng)來(lái)看它似乎能夠這樣做,這樣命名是因?yàn)樗鄶?shù)情況下確實(shí)是在清除數(shù)據(jù)時(shí)使用。

clear ()方法的通俗解釋是“一切為默認(rèn)”。

final Buffer flip()方法的作用:反轉(zhuǎn)此緩沖區(qū)。首先將限制設(shè)置為當(dāng)前位置,然后將位置設(shè)置為0。如果已定義了標(biāo)記,則丟棄該標(biāo)記,方法內(nèi)部的源代碼如下:

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

flip()方法的通俗解釋是“縮小limit的范圍,類(lèi)似于String.subString(0, endIndex)方法”。

rewind()、clear()和flip()方法在官方幫助文檔中的解釋如下。

?rewind():使緩沖區(qū)為“重新讀取”已包含的數(shù)據(jù)做好準(zhǔn)備,它使限制保持不變,將位置設(shè)置為0。

?clear():使緩沖區(qū)為一系列新的通道讀取或相對(duì)put(value)操作做好準(zhǔn)備,即它將限制設(shè)置為容量大小,將位置設(shè)置為0。

?flip():使緩沖區(qū)為一系列新的通道寫(xiě)入或相對(duì)get(value)操作做好準(zhǔn)備,即它將限制設(shè)置為當(dāng)前位置,然后將位置設(shè)置為0。

這3個(gè)方法的側(cè)重點(diǎn)在于:

1)rewind()方法的側(cè)重點(diǎn)在“重新”,在重新讀取、重新寫(xiě)入時(shí)可以使用;

2)clear()方法的側(cè)重點(diǎn)在“還原一切狀態(tài)”;

3)flip()方法的側(cè)重點(diǎn)在substring截取。

示例代碼如下:

public class Test14 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3, 4, 5 };
    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
    System.out.println("capacity=" + byteBuffer.capacity() + " limit=" +
        byteBuffer.limit() + " position="
            + byteBuffer.position());
    byteBuffer.position(1);
    byteBuffer.limit(3);
    byteBuffer.mark();
    System.out.println("capacity=" + byteBuffer.capacity() + " limit=" +
        byteBuffer.limit() + " position="
            + byteBuffer.position());
    byteBuffer.rewind();
    System.out.println("capacity=" + byteBuffer.capacity() + " limit=" +
        byteBuffer.limit() + " position="
            + byteBuffer.position());
    byteBuffer.reset();
}
}

程序運(yùn)行結(jié)果如下:

capacity=5 limit=5 position=0
capacity=5 limit=3 position=1
capacity=5 limit=3 position=0
Exception in thread "main" java.nio.InvalidMarkException
    at java.nio.Buffer.reset(Buffer.java:306)
    at BufferAPITest.Test14.main(Test14.java:24)

1.3.14 獲得偏移量

final int arrayOffset()方法的作用:返回此緩沖區(qū)的底層實(shí)現(xiàn)數(shù)組中第一個(gè)緩沖區(qū)元素的偏移量,這個(gè)值在文檔中標(biāo)注為“可選操作”,也就是子類(lèi)可以不處理這個(gè)值。該方法的內(nèi)部源代碼如下:

public final int arrayOffset() {
    if (hb == null)
        throw new UnsupportedOperationException();
    if (isReadOnly)
        throw new ReadOnlyBufferException();
    return offset;
}

實(shí)例變量offset是在執(zhí)行HeapByteBuffer類(lèi)的構(gòu)造方法時(shí)傳入的,示例代碼如下:

HeapByteBuffer(byte[] buf, int off, int len) {
    super(-1, off, off + len, buf.length, buf, 0);
}

最后一個(gè)參數(shù)0就是對(duì)ByteBuffer類(lèi)的offset實(shí)例變量進(jìn)行賦值,源代碼如下:

ByteBuffer(int mark, int pos, int lim, int cap,    //包級(jí)訪(fǎng)問(wèn)
              byte[] hb, int offset)
{
    super(mark, pos, lim, cap);
    this.hb = hb;
    this.offset = offset;
}

示例代碼如下:

public class Test15 {
public static void main(String[] args) {
    byte[] byteArray = new byte[] { 1, 2, 3 };
    ByteBuffer bytebuffer = ByteBuffer.wrap(byteArray);
    System.out.println("bytebuffer.arrayOffset=" + bytebuffer.arrayOffset());
}
}

程序運(yùn)行結(jié)果如下:

bytebuffer.arrayOffset=0

在上面的示例中,不管怎么進(jìn)行操作,arrayOffset()方法的返回值永遠(yuǎn)是0,非0的情況將在后面的章節(jié)介紹。

1.3.15 使用List.toArray(T[])轉(zhuǎn)成數(shù)組類(lèi)型

如果List中存儲(chǔ)ByteBuffer數(shù)據(jù)類(lèi)型,則可以使用List中的toArray()方法轉(zhuǎn)成ByteBuffer[]數(shù)組類(lèi)型,示例代碼如下:

    public class Test16 {
    public static void main(String[] args) {
        ByteBuffer buffer1 = ByteBuffer.wrap(new byte[] { 'a', 'b', 'c' });
        ByteBuffer buffer2 = ByteBuffer.wrap(new byte[] { 'x', 'y', 'z' });
        ByteBuffer buffer3 = ByteBuffer.wrap(new byte[] { '1', '2', '3' });
        List<ByteBuffer> list = new ArrayList<>();
        list.add(buffer1);
        list.add(buffer2);
        list.add(buffer3);
       
        ByteBuffer[] byteBufferArray = new ByteBuffer[list.size()];
        list.toArray(byteBufferArray);
        System.out.println(byteBufferArray.length);
        for (int i = 0; i < byteBufferArray.length; i++) {
            ByteBuffer eachByteBuffer = byteBufferArray[i];
            while (eachByteBuffer.hasRemaining()) {
                System.out.print((char) eachByteBuffer.get());
            }
            System.out.println();
        }
}
}

程序運(yùn)行結(jié)果如下:

3
abc
xyz
123

至此,已經(jīng)將Buffer類(lèi)的全部API進(jìn)行了介紹,熟練掌握父類(lèi)Buffer的API對(duì)學(xué)習(xí)子類(lèi)有非常大的幫助,因?yàn)檫@些API是可以被子類(lèi)所繼承并使用的。

主站蜘蛛池模板: 中江县| 梨树县| 金沙县| 靖西县| 鄂尔多斯市| 杂多县| 三门县| 兴义市| 三门峡市| 泸定县| 巧家县| 玉屏| 会同县| 自贡市| 扶风县| 元江| 翼城县| 尤溪县| 黑山县| 翼城县| 定结县| 田林县| 合山市| 梁山县| 额济纳旗| 平原县| 海淀区| 汝城县| 桦川县| 谢通门县| 新化县| 扎囊县| 汾阳市| 普格县| 汪清县| 工布江达县| 新郑市| 民勤县| 永吉县| 建德市| 松原市|