使用ByteBuffer

ByteBuffer類提供了6類操作。

  1. 以絕對位置和相對位置讀寫單個字節的get()和put()方法
  2. 使用相對批量get(byte[] dst)方法可以將緩衝區中的連續字節傳輸到byte[] dst目標數組中。
  3. 使用相對批量put(byte[] src)方法可以將byte[]數組或其他字節緩衝區中的連續字節存儲到此緩衝區中。
  4. 使用相對和絕對getType和putType方法可以按照字節順序在字節序列中讀寫其他基本數據類型的值,方法getType和putType可以進行數據類型的自動轉換。
  5. 提供了創建視圖緩衝區的方法,這些方法允許將字節緩衝區視爲包含其他基本類型值的緩衝區,這些方法有asCharBuffer()、asDoubleBuffer()、asFloatBuffer()、asIntBuffer()、asLongBuffer()、asShortBuffer()。
  6. 提供了對字節緩衝區進行壓縮(compacting)、複製(duplicating)和截取(slicing)的方法。

創建堆緩衝區和直接緩衝區

字節緩衝區分爲直接字節緩衝區(JVM會盡量直接對內核空間進行IO操作,避免將緩衝區內容複製到中間緩衝區,提高效率)和非直接字節緩衝區。
allocateDirect()創建直接字節緩衝區,通過工廠方法allocateDirect()返回的緩衝區進行內存的分配和釋放所需要的時間成本通常要高於非直接緩衝區。

allocate源碼:

/**
     * Allocates a new direct byte buffer.
     *
     * <p> The new buffer's position will be zero, its limit will be its
     * capacity, its mark will be undefined, and each of its elements will be
     * initialized to zero.  Whether or not it has a
     * {@link #hasArray backing array} is unspecified.
     *
     * @param  capacity
     *         The new buffer's capacity, in bytes
     *
     * @return  The new byte buffer
     *
     * @throws  IllegalArgumentException
     *          If the <tt>capacity</tt> is a negative integer
     */
    public static ByteBuffer allocateDirect(int capacity) {
        return new DirectByteBuffer(capacity);
    }
    
    /**
     * Allocates a new byte buffer.
     *
     * <p> The new buffer's position will be zero, its limit will be its
     * capacity, its mark will be undefined, and each of its elements will be
     * initialized to zero.  It will have a {@link #array backing array},
     * and its {@link #arrayOffset array offset} will be zero.
     *
     * @param  capacity
     *         The new buffer's capacity, in bytes
     *
     * @return  The new byte buffer
     *
     * @throws  IllegalArgumentException
     *          If the <tt>capacity</tt> is a negative integer
     */
    public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapByteBuffer(capacity, capacity);
    }

直接緩衝區與非直接緩衝區運行效率比較

long begin = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocateDirect(1000000000);
for (int i = 0; i < 1000000000; i++) {
    buffer.put((byte)100);
}
System.out.println(System.currentTimeMillis() - begin);

output:
	1896
long begin = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocate(1000000000);
 for (int i = 0; i < 1000000000; i++) {
     buffer.put((byte)100);
 }
 System.out.println(System.currentTimeMillis() - begin);

output:
	2575

直接緩衝區運行效率要高些。直接緩衝區(DIrectByteBuffer)內部使用sun.misc.Unsafe類進行值的處理。Unsafe的作用是JVM與操作系統進行直接通信,提高程序運行的效率。

public ByteBuffer put(byte x) {
        unsafe.putByte(ix(nextPutIndex()), ((x)));
        return this;
}

非直接緩衝區(HeapByteBuffer)在內部直接對byte[] hb字節數組進行操作,而且還是在JVM的堆中進行數據處理,運行效率相對慢些。

public ByteBuffer put(byte x) {
        hb[ix(nextPutIndex())] = x;
        return this;
 }

包裝wrap數據的處理

wrap(byte[] array):

/**
     * Wraps a byte array into a buffer.
     *
     * <p> The new buffer will be backed by the given byte array;
     * that is, modifications to the buffer will cause the array to be modified
     * and vice versa.  The new buffer's capacity and limit will be
     * <tt>array.length</tt>, its position will be zero, and its mark will be
     * undefined.  Its {@link #array backing array} will be the
     * given array, and its {@link #arrayOffset array offset>} will
     * be zero.  </p>
     *
     * @param  array
     *         The array that will back this buffer
     *
     * @return  The new byte buffer
     */
    public static ByteBuffer wrap(byte[] array) {
        return wrap(array, 0, array.length);
    }

wrap(byte[] array, int offset, int length):

 /**
     * Wraps a byte array into a buffer.
     *
     * <p> The new buffer will be backed by the given byte array;
     * that is, modifications to the buffer will cause the array to be modified
     * and vice versa.  The new buffer's capacity will be
     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
     * {@link #array backing array} will be the given array, and
     * its {@link #arrayOffset array offset} will be zero.  </p>
     *
     * @param  array
     *         The array that will back the new buffer
     *
     * @param  offset
     *         The offset of the subarray to be used; must be non-negative and
     *         no larger than <tt>array.length</tt>.  The new buffer's position
     *         will be set to this value.
     *
     * @param  length
     *         The length of the subarray to be used;
     *         must be non-negative and no larger than
     *         <tt>array.length - offset</tt>.
     *         The new buffer's limit will be set to <tt>offset + length</tt>.
     *
     * @return  The new byte buffer
     *
     * @throws  IndexOutOfBoundsException
     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
     *          parameters do not hold
     */
    public static ByteBuffer wrap(byte[] array, int offset, int length)
    {
        try {
            return new HeapByteBuffer(array, offset, length);
        } catch (IllegalArgumentException x) {
            throw new IndexOutOfBoundsException();
        }
    }

注意:wrap(byte[] array, int offset, int length)參數offset只是設置緩衝區的position值,length確定limit值

Demo:

byte[] byteArr = new byte[]{1,2,3,4,5,6,7,8};
ByteBuffer byteBuffer1 = ByteBuffer.wrap(byteArr);
ByteBuffer byteBuffer2 = ByteBuffer.wrap(byteArr,2,4);
System.out.println("bytebuffer1 capacity=" + byteBuffer1.capacity() + " limit=" + byteBuffer1.limit() + " position=" + byteBuffer1.position());
System.out.println("bytebuffer2 capacity=" + byteBuffer2.capacity() + " limit=" + byteBuffer2.limit() + " position=" + byteBuffer2.position());

output:
	bytebuffer1 capacity=8 limit=8 position=0
	bytebuffer2 capacity=8 limit=6 position=2

put(byte[] b)和get()方法的使用

get和put分別提供兩種操作,相對位置和絕對位置操作。執行相對位置讀或者寫操作後,position遞增

/**
     * Relative <i>get</i> method.  Reads the byte at this buffer's
     * current position, and then increments the position.
     *
     * @return  The byte at the buffer's current position
     *
     * @throws  BufferUnderflowException
     *          If the buffer's current position is not smaller than its limit
     */
    public abstract byte get();

    /**
     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes the given byte into this buffer at the current
     * position, and then increments the position. </p>
     *
     * @param  b
     *         The byte to be written
     *
     * @return  This buffer
     *
     * @throws  BufferOverflowException
     *          If this buffer's current position is not smaller than its limit
     *
     * @throws  ReadOnlyBufferException
     *          If this buffer is read-only
     */
    public abstract ByteBuffer put(byte b);

    /**
     * Absolute <i>get</i> method.  Reads the byte at the given
     * index.
     *
     * @param  index
     *         The index from which the byte will be read
     *
     * @return  The byte at the given index
     *
     * @throws  IndexOutOfBoundsException
     *          If <tt>index</tt> is negative
     *          or not smaller than the buffer's limit
     */
    public abstract byte get(int index);

    /**
     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes the given byte into this buffer at the given
     * index. </p>
     *
     * @param  index
     *         The index at which the byte will be written
     *
     * @param  b
     *         The byte value to be written
     *
     * @return  This buffer
     *
     * @throws  IndexOutOfBoundsException
     *          If <tt>index</tt> is negative
     *          or not smaller than the buffer's limit
     *
     * @throws  ReadOnlyBufferException
     *          If this buffer is read-only
     */
    public abstract ByteBuffer put(int index, byte b);

put(byte[] src, int offset, int length)和get(byte[] dst, int offset, int length)

相對批量put方法,將給定源數組中的字節傳輸到此緩衝區當前位置中。

/**
     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> This method transfers bytes into this buffer from the given
     * source array.  If there are more bytes to be copied from the array
     * than remain in this buffer, that is, if
     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
     * bytes are transferred and a {@link BufferOverflowException} is
     * thrown.
     *
     * <p> Otherwise, this method copies <tt>length</tt> bytes from the
     * given array into this buffer, starting at the given offset in the array
     * and at the current position of this buffer.  The position of this buffer
     * is then incremented by <tt>length</tt>.
     *
     * <p> In other words, an invocation of this method of the form
     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
     * the loop
     *
     * <pre>{@code
     *     for (int i = off; i < off + len; i++)
     *         dst.put(a[i]);
     * }</pre>
     *
     * except that it first checks that there is sufficient space in this
     * buffer and it is potentially much more efficient.
     *
     * @param  src
     *         The array from which bytes are to be read
     *
     * @param  offset
     *         The offset within the array of the first byte to be read;
     *         must be non-negative and no larger than <tt>array.length</tt>
     *
     * @param  length
     *         The number of bytes to be read from the given array;
     *         must be non-negative and no larger than
     *         <tt>array.length - offset</tt>
     *
     * @return  This buffer
     *
     * @throws  BufferOverflowException
     *          If there is insufficient space in this buffer
     *
     * @throws  IndexOutOfBoundsException
     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
     *          parameters do not hold
     *
     * @throws  ReadOnlyBufferException
     *          If this buffer is read-only
     */
    public ByteBuffer put(byte[] src, int offset, int length) {
        checkBounds(offset, length, src.length);
        if (length > remaining())
            throw new BufferOverflowException();
        int end = offset + length;
        for (int i = offset; i < end; i++)
            this.put(src[i]);
        return this;
    }

dst.put(src,offset,length)等同於下面的循環語句

for(int i = offset;i < offset + length;i++){
	dst.put(a[i])
}

相對批量get方法,將緩衝區當前位置的字節傳輸到給定的目標數組中。

 // -- Bulk get operations --

    /**
     * Relative bulk <i>get</i> method.
     *
     * <p> This method transfers bytes from this buffer into the given
     * destination array.  If there are fewer bytes remaining in the
     * buffer than are required to satisfy the request, that is, if
     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
     * bytes are transferred and a {@link BufferUnderflowException} is
     * thrown.
     *
     * <p> Otherwise, this method copies <tt>length</tt> bytes from this
     * buffer into the given array, starting at the current position of this
     * buffer and at the given offset in the array.  The position of this
     * buffer is then incremented by <tt>length</tt>.
     *
     * <p> In other words, an invocation of this method of the form
     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
     * the loop
     *
     * <pre>{@code
     *     for (int i = off; i < off + len; i++)
     *         dst[i] = src.get():
     * }</pre>
     *
     * except that it first checks that there are sufficient bytes in
     * this buffer and it is potentially much more efficient.
     *
     * @param  dst
     *         The array into which bytes are to be written
     *
     * @param  offset
     *         The offset within the array of the first byte to be
     *         written; must be non-negative and no larger than
     *         <tt>dst.length</tt>
     *
     * @param  length
     *         The maximum number of bytes to be written to the given
     *         array; must be non-negative and no larger than
     *         <tt>dst.length - offset</tt>
     *
     * @return  This buffer
     *
     * @throws  BufferUnderflowException
     *          If there are fewer than <tt>length</tt> bytes
     *          remaining in this buffer
     *
     * @throws  IndexOutOfBoundsException
     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
     *          parameters do not hold
     */
    public ByteBuffer get(byte[] dst, int offset, int length) {
        checkBounds(offset, length, dst.length);
        if (length > remaining())
            throw new BufferUnderflowException();
        int end = offset + length;
        for (int i = offset; i < end; i++)
            dst[i] = get();
        return this;
    }

Demo:

		byte[] byteArr1 = new byte[]{1,2,3,4,5,6,7,8};
        byte[] byteArr2 = new byte[]{55,66,77,88};
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        byteBuffer.put(byteArr1);
        byteBuffer.position(2);
        byteBuffer.put(byteArr2,1,3);

        byte[] getByte = byteBuffer.array();
        for (int i = 0; i < getByte.length; i++) {
            System.out.print(getByte[i] + " ");
        }
        System.out.println();
        byteBuffer.position(1);
        byte[] byteArrOut = new byte[byteBuffer.capacity()];
        byteBuffer.get(byteArrOut,3,4);
        for (int i = 0; i < byteArrOut.length; i++) {
            System.out.print(byteArrOut[i] + " ");
        }
        System.out.println();

output:
	1 2 66 77 88 6 7 8 0 0 
	0 0 0 2 66 77 88 0 0 0 

put(ByteBuffer src)

相對批量put方法,將給定源緩衝區的剩餘字節傳輸到此緩衝區的當前位置。

 // -- Bulk put operations --

    /**
     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> This method transfers the bytes remaining in the given source
     * buffer into this buffer.  If there are more bytes remaining in the
     * source buffer than in this buffer, that is, if
     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
     * then no bytes are transferred and a {@link
     * BufferOverflowException} is thrown.
     *
     * <p> Otherwise, this method copies
     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> bytes from the given
     * buffer into this buffer, starting at each buffer's current position.
     * The positions of both buffers are then incremented by <i>n</i>.
     *
     * <p> In other words, an invocation of this method of the form
     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
     *
     * <pre>
     *     while (src.hasRemaining())
     *         dst.put(src.get()); </pre>
     *
     * except that it first checks that there is sufficient space in this
     * buffer and it is potentially much more efficient.
     *
     * @param  src
     *         The source buffer from which bytes are to be read;
     *         must not be this buffer
     *
     * @return  This buffer
     *
     * @throws  BufferOverflowException
     *          If there is insufficient space in this buffer
     *          for the remaining bytes in the source buffer
     *
     * @throws  IllegalArgumentException
     *          If the source buffer is this buffer
     *
     * @throws  ReadOnlyBufferException
     *          If this buffer is read-only
     */
    public ByteBuffer put(ByteBuffer src) {
        if (src == this)
            throw new IllegalArgumentException();
        if (isReadOnly())
            throw new ReadOnlyBufferException();
        int n = src.remaining();
        if (n > remaining())
            throw new BufferOverflowException();
        for (int i = 0; i < n; i++)
            put(src.get());
        return this;
    }

Demo

		byte[] byteArr1 = new byte[]{1,2,3,4,5,6,7,8};
        ByteBuffer buffer1 = ByteBuffer.wrap(byteArr1);

        byte[] byteArr2 = new byte[]{55,66,77,88};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArr2);

        buffer1.position(4);
        buffer2.position(1);

        buffer1.put(buffer2);

        System.out.println(buffer1.position());
        System.out.println(buffer2.position());

        byte[] byteArrOut = buffer1.array();
        for (int i = 0; i < byteArrOut.length; i++) {
            System.out.print(byteArrOut[i] + " ");
        }
        System.out.println();
    
  output:
  		7
		4
		1 2 3 4 66 77 88 8 

putType()和getType()

putChar(char value)

 /**
     * Relative <i>put</i> method for writing a char
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes two bytes containing the given char value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by two.  </p>
     *
     * @param  value
     *         The char value to be written
     *
     * @return  This buffer
     *
     * @throws  BufferOverflowException
     *          If there are fewer than two bytes
     *          remaining in this buffer
     *
     * @throws  ReadOnlyBufferException
     *          If this buffer is read-only
     */
    public abstract ByteBuffer putChar(char value);

putChar(int index, char value)
putDouble(double value) //8個字節
putDouble(int index, double value)
putFloat(float value) //4個字節
putFloat(int index, float value)
putInt(int value) //4個字節
putInt(int index, int value)
putLong(long value) //8個字節
putLong(int index, int value)
putShort(short value) //2個字節
putShort(int index, short value)

slice()方法

創建新的字節緩衝區,其內容是此緩衝區內容的共享子序列。新緩衝區的內容將從此緩衝區的當前位置開始。此緩衝區內容的更改子新緩衝區是可見的,反之亦然;兩個緩衝區的位置、限制和標記值是相互獨立的。新緩衝區的位置將爲0,其容量和限制將爲此緩衝區中所剩餘的字節數量,標記是不確定的

 /**
     * Creates a new byte buffer whose content is a shared subsequence of
     * this buffer's content.
     *
     * <p> The content of the new buffer will start at this buffer's current
     * position.  Changes to this buffer's content will be visible in the new
     * buffer, and vice versa; the two buffers' position, limit, and mark
     * values will be independent.
     *
     * <p> The new buffer's position will be zero, its capacity and its limit
     * will be the number of bytes remaining in this buffer, and its mark
     * will be undefined.  The new buffer will be direct if, and only if, this
     * buffer is direct, and it will be read-only if, and only if, this buffer
     * is read-only.  </p>
     *
     * @return  The new byte buffer
     */
    public abstract ByteBuffer slice();

Demo

 		byte[] byteArr1 = new byte[]{1,2,3,4,5,6,7,8};
        ByteBuffer buffer1 = ByteBuffer.wrap(byteArr1);

        buffer1.position(4);
        ByteBuffer buffer2 = buffer1.slice();
        System.out.println("buffer1 position=" + buffer1.position() + " capacity=" + buffer1.capacity() + " limit=" + buffer1.limit());
        System.out.println("buffer2 position=" + buffer2.position() + " capacity=" + buffer2.capacity() + " limit=" + buffer2.limit());

        buffer2.put(0,(byte)100);
        byte[] byteArrOut1 = buffer1.array();
        for (int i = 0; i < byteArrOut1.length; i++) {
            System.out.print(byteArrOut1[i] + " ");
        }
        System.out.println();
        byte[] byteArrOut2 = buffer1.array();
        for (int i = 0; i < byteArrOut2.length; i++) {
            System.out.print(byteArrOut2[i] + " ");
        }
        System.out.println();

output:
	buffer1 position=4 capacity=8 limit=8
	buffer2 position=0 capacity=4 limit=4
	1 2 3 4 100 6 7 8 
	1 2 3 4 100 6 7 8 

轉換爲CharBuffer字符緩衝區及中文的處理

asCharBuffer

/**
     * Creates a view of this byte buffer as a char buffer.
     *
     * <p> The content of the new buffer will start at this buffer's current
     * position.  Changes to this buffer's content will be visible in the new
     * buffer, and vice versa; the two buffers' position, limit, and mark
     * values will be independent.
     *
     * <p> The new buffer's position will be zero, its capacity and its limit
     * will be the number of bytes remaining in this buffer divided by
     * two, and its mark will be undefined.  The new buffer will be direct
     * if, and only if, this buffer is direct, and it will be read-only if, and
     * only if, this buffer is read-only.  </p>
     *
     * @return  A new char buffer
     */
    public abstract CharBuffer asCharBuffer();

Demo

		byte[] byteArr1 = "我是好學生".getBytes();
        System.out.println(Charset.defaultCharset().name());

        ByteBuffer byteBuffer = ByteBuffer.wrap(byteArr1);
        System.out.println(byteBuffer.getClass().getName());

        CharBuffer charBuffer = byteBuffer.asCharBuffer();
        System.out.println(charBuffer.getClass().getName());

        System.out.println("byteBuffer position=" + byteBuffer.position() + " capacity=" + byteBuffer.capacity() + " limit=" + byteBuffer.limit());
        System.out.println("charBuffer position=" + charBuffer.position() + " capacity=" + charBuffer.capacity() + " limit=" + charBuffer.limit());

        charBuffer.position(0);
        for (int i = 0; i < charBuffer.capacity(); i++) {
            System.out.print(charBuffer.get() + " ");
        }
        System.out.println();
        
output:
	UTF-8
	java.nio.HeapByteBuffer
	java.nio.ByteBufferAsCharBufferB	
	byteBuffer position=0 capacity=15 limit=15
	charBuffer position=0 capacity=7 limit=7
	 釦 颯  뷥 궦  

出現了亂碼。
byteArr1數組中存儲的編碼爲UTF-8,wrap後,緩衝區存儲的編碼也爲UTF-8,asCharBuffer後,UTF-8編碼的ByteBuffer轉換成UTF-8的CharBuffer,在調用charBuffer的get方法時,以UTF-16BE的編碼格式獲得中文時出現編碼不匹配的情況,出現了亂碼

解決方法1:
將中文按utf-16be編碼轉化成字節數組

byte[] byteArr1 = "我是好學生".getBytes("utf-16BE");

解決方法2:

byte[] byteArr1 = "我是好學生".getBytes("utf-8");
……
CharBuffer charBuffer = Charset.forName("utf-8").decode(byteBuffer)
……

設置與獲得字節順序

order()方法與字節數據排列的順序有關,不同的CPU在讀取字節時的順序是不一樣的,有的CPU從高位開始讀,有的CPU從低位開始讀,order(ByteOrder bo)設置字節的排列順序。
ByteOrder order()方法的作用:獲取此緩衝區的字節順序。新創建的字節緩衝區的順序始終爲BIG_ENDIAN。
1):public static final ByteOrder BIG_ENDIAN:表示BIG_ENDIAN字節順序的常量。按照此順序,多字節值的字節順序是從最高有效位到最低有效位的。
2):public static final ByteOrder LITTLE_ENDIAN:表示LITTLE_ENDIAN字節順序的常量。按照此順序,多字節值的字節順序是從最低有效位到最高有效位的。
order(ByteOrder bo):修改此緩衝區的字節順序,默認情況下,字節緩衝區的初始順序是BIG_ENDIAN。

創建只讀緩衝區

asReadOnlyBuffer():創建共享此緩衝區內容的新的只讀字節緩衝區。新緩衝區的內容將爲此緩衝區的內容。此緩衝區內容的更改在新緩衝區可見,新緩衝區內容是隻讀的

		byte[] byteArrIn = {1,2,3,4,5};
        ByteBuffer buffer1 = ByteBuffer.wrap(byteArrIn);
        ByteBuffer buffer2 = buffer1.asReadOnlyBuffer();
        System.out.println(buffer1.isReadOnly());
        System.out.println(buffer2.isReadOnly());
        buffer2.rewind();
        buffer2.put((byte)111);

output:
	false
	true
	java.nio.ReadOnlyBufferException
		at java.nio.HeapByteBufferR.put(HeapByteBufferR.java:172)

壓縮緩衝區

compact:將緩衝區的當前位置和限制之間的字節複製到緩衝區的開始處,即將索引p=position()處的字節複製到索引0處,將索引p+1處的字節複製到索引1處,依此類推,直到將索引limit()-1處的自己複製到索引n = limit() - 1 -p處。然後,將緩衝區的的位置設置爲n+1,並將其限制設置爲其容量。

/**
     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> The bytes between the buffer's current position and its limit,
     * if any, are copied to the beginning of the buffer.  That is, the
     * byte at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
     * to index zero, the byte at index <i>p</i>&nbsp;+&nbsp;1 is copied
     * to index one, and so forth until the byte at index
     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
     * The buffer's position is then set to <i>n+1</i> and its limit is set to
     * its capacity.  The mark, if defined, is discarded.
     *
     * <p> The buffer's position is set to the number of bytes copied,
     * rather than to zero, so that an invocation of this method can be
     * followed immediately by an invocation of another relative <i>put</i>
     * method. </p>
     *

     *
     * <p> Invoke this method after writing data from a buffer in case the
     * write was incomplete.  The following loop, for example, copies bytes
     * from one channel to another via the buffer <tt>buf</tt>:
     *
     * <blockquote><pre>{@code
     *   buf.clear();          // Prepare buffer for use
     *   while (in.read(buf) >= 0 || buf.position != 0) {
     *       buf.flip();
     *       out.write(buf);
     *       buf.compact();    // In case of partial write
     *   }
     * }</pre></blockquote>
     *

     *
     * @return  This buffer
     *
     * @throws  ReadOnlyBufferException
     *          If this buffer is read-only
     */
    public abstract ByteBuffer compact();

比較緩衝區內容

方法一:
equals:

/**
     * Tells whether or not this buffer is equal to another object.
     * <p> Two byte buffers are equal if, and only if,
     * <ol>
     *   <li><p> They have the same element type,  </p></li>
     *   <li><p> They have the same number of remaining elements, and
     *   </p></li>
     *   <li><p> The two sequences of remaining elements, considered
     *   independently of their starting positions, are pointwise equal.
     * <p> A byte buffer is not equal to any other type of object.  </p>
    
     * @param  ob  The object to which this buffer is to be compared
     *
     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
     *           given object
     */
    public boolean equals(Object ob) {
        if (this == ob)
            return true;
        if (!(ob instanceof ByteBuffer))
            return false;
        ByteBuffer that = (ByteBuffer)ob;
        if (this.remaining() != that.remaining())
            return false;
        int p = this.position();
        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
            if (!equals(this.get(i), that.get(j)))
                return false;
        return true;
    }
  1. 判斷是否是自身,如果是自身,返回true
  2. 判斷是不是ByteBuffer類的實例,如果不是,返回false;
  3. 判斷remaining是否一樣,不一樣,返回false;
  4. 判斷position和limit是否一樣,有一個不一樣,返回false。

從源碼看,兩個緩衝區的capacity可以不一樣。

方法二:
compareTo

 /**
     * Compares this buffer to another.
     *
     * <p> Two byte buffers are compared by comparing their sequences of
     * remaining elements lexicographically, without regard to the starting
     * position of each sequence within its corresponding buffer.
     * Pairs of {@code byte} elements are compared as if by invoking
     * {@link Byte#compare(byte,byte)}.
     * <p> A byte buffer is not comparable to any other type of object.
     *
     * @return  A negative integer, zero, or a positive integer as this buffer
     *          is less than, equal to, or greater than the given buffer
     */
    public int compareTo(ByteBuffer that) {
        int n = this.position() + Math.min(this.remaining(), that.remaining());
        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
            int cmp = compare(this.get(i), that.get(j));
            if (cmp != 0)
                return cmp;
        }
        return this.remaining() - that.remaining();
    }

1)判斷兩個ByteBuffer的範圍是從當前ByteBuffer對象的當前位置開始,以兩個ByteBuffer對象最小的remaining結束,說明判斷的範圍是remaining交集
2) 如果在開始和結束的範圍之間有一個字節不同,則返回兩者的減數
3) 如果在開始和結束的範圍之間每個字節都相同,則返回兩者remaining的減數

複製緩衝區

 /**
     * Creates a new byte buffer that shares this buffer's content.
     *
     * <p> The content of the new buffer will be that of this buffer.  Changes
     * to this buffer's content will be visible in the new buffer, and vice
     * versa; the two buffers' position, limit, and mark values will be
     * independent.
     *
     * <p> The new buffer's capacity, limit, position, and mark values will be
     * identical to those of this buffer.  The new buffer will be direct if,
     * and only if, this buffer is direct, and it will be read-only if, and
     * only if, this buffer is read-only.  </p>
     *
     * @return  The new byte buffer
     */
    public abstract ByteBuffer duplicate();

對緩衝區擴容

 public static ByteBuffer extendsSize(ByteBuffer byteBuffer,int extendSize){
        ByteBuffer newByteBuffer = ByteBuffer.allocate(byteBuffer.capacity() + extendSize);
        newByteBuffer.put(byteBuffer);
        return newByteBuffer;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章