美文网首页
java.nio.ByteBuffer源码

java.nio.ByteBuffer源码

作者: small瓜瓜 | 来源:发表于2019-06-09 16:51 被阅读0次

    java nio 的重点Buffer,为了更深入了解其原理,看了下它的源码,在源码实现上还是很简单的,
    ByteBuffer的子类HeapByteBuffer实现了它的各种操作,底层是通过byte数组对数据进行保存的。

    /**
     * A byte buffer.
     *
     * <p> This class defines six categories of operations upon
     * byte buffers:
     *
     * <ul>
     *
     * <li><p> Absolute and relative {@link #get() <i>get</i>} and
     * {@link #put(byte) <i>put</i>} methods that read and write
     * single bytes; </p></li>
     *
     * <li><p> Relative {@link #get(byte[]) <i>bulk get</i>}
     * methods that transfer contiguous sequences of bytes from this buffer
     * into an array; </p></li>
     *
     * <li><p> Relative {@link #put(byte[]) <i>bulk put</i>}
     * methods that transfer contiguous sequences of bytes from a
     * byte array or some other byte
     * buffer into this buffer; </p></li>
     *
     *
     *
     * <li><p> Absolute and relative {@link #getChar() <i>get</i>}
     * and {@link #putChar(char) <i>put</i>} methods that read and
     * write values of other primitive types, translating them to and from
     * sequences of bytes in a particular byte order; </p></li>
     *
     * <li><p> Methods for creating <i><a href="#views">view buffers</a></i>,
     * which allow a byte buffer to be viewed as a buffer containing values of
     * some other primitive type; and </p></li>
     *
     *
     *
     * <li><p> Methods for {@link #compact compacting}, {@link
     * #duplicate duplicating}, and {@link #slice slicing}
     * a byte buffer.  </p></li>
     *
     * </ul>
     *
     * <p> Byte buffers can be created either by {@link #allocate
     * <i>allocation</i>}, which allocates space for the buffer's
     * <p>
     * <p>
     * <p>
     * content, or by {@link #wrap(byte[]) <i>wrapping</i>} an
     * existing byte array  into a buffer.
     *
     *
     * <a name="direct"></a>
     * <h2> Direct <i>vs.</i> non-direct buffers </h2>
     *
     * <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>.  Given a
     * direct byte buffer, the Java virtual machine will make a best effort to
     * perform native I/O operations directly upon it.  That is, it will attempt to
     * avoid copying the buffer's content to (or from) an intermediate buffer
     * before (or after) each invocation of one of the underlying operating
     * system's native I/O operations.
     *
     * <p> A direct byte buffer may be created by invoking the {@link
     * #allocateDirect(int) allocateDirect} factory method of this class.  The
     * buffers returned by this method typically have somewhat higher allocation
     * and deallocation costs than non-direct buffers.  The contents of direct
     * buffers may reside outside of the normal garbage-collected heap, and so
     * their impact upon the memory footprint of an application might not be
     * obvious.  It is therefore recommended that direct buffers be allocated
     * primarily for large, long-lived buffers that are subject to the underlying
     * system's native I/O operations.  In general it is best to allocate direct
     * buffers only when they yield a measureable gain in program performance.
     *
     * <p> A direct byte buffer may also be created by {@link
     * java.nio.channels.FileChannel#map mapping} a region of a file
     * directly into memory.  An implementation of the Java platform may optionally
     * support the creation of direct byte buffers from native code via JNI.  If an
     * instance of one of these kinds of buffers refers to an inaccessible region
     * of memory then an attempt to access that region will not change the buffer's
     * content and will cause an unspecified exception to be thrown either at the
     * time of the access or at some later time.
     *
     * <p> Whether a byte buffer is direct or non-direct may be determined by
     * invoking its {@link #isDirect isDirect} method.  This method is provided so
     * that explicit buffer management can be done in performance-critical code.
     *
     *
     * <a name="bin"></a>
     * <h2> Access to binary data </h2>
     *
     * <p> This class defines methods for reading and writing values of all other
     * primitive types, except <tt>boolean</tt>.  Primitive values are translated
     * to (or from) sequences of bytes according to the buffer's current byte
     * order, which may be retrieved and modified via the {@link #order order}
     * methods.  Specific byte orders are represented by instances of the {@link
     * ByteOrder} class.  The initial order of a byte buffer is always {@link
     * ByteOrder#BIG_ENDIAN BIG_ENDIAN}.
     *
     * <p> For access to heterogeneous binary data, that is, sequences of values of
     * different types, this class defines a family of absolute and relative
     * <i>get</i> and <i>put</i> methods for each type.  For 32-bit floating-point
     * values, for example, this class defines:
     *
     * <blockquote><pre>
     * float  {@link #getFloat()}
     * float  {@link #getFloat(int) getFloat(int index)}
     *  void  {@link #putFloat(float) putFloat(float f)}
     *  void  {@link #putFloat(int, float) putFloat(int index, float f)}</pre></blockquote>
     *
     * <p> Corresponding methods are defined for the types <tt>char</tt>,
     * <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and <tt>double</tt>.  The index
     * parameters of the absolute <i>get</i> and <i>put</i> methods are in terms of
     * bytes rather than of the type being read or written.
     *
     * <a name="views"></a>
     *
     * <p> For access to homogeneous binary data, that is, sequences of values of
     * the same type, this class defines methods that can create <i>views</i> of a
     * given byte buffer.  A <i>view buffer</i> is simply another buffer whose
     * content is backed by the byte buffer.  Changes to the byte buffer's content
     * will be visible in the view buffer, and vice versa; the two buffers'
     * position, limit, and mark values are independent.  The {@link
     * #asFloatBuffer() asFloatBuffer} method, for example, creates an instance of
     * the {@link FloatBuffer} class that is backed by the byte buffer upon which
     * the method is invoked.  Corresponding view-creation methods are defined for
     * the types <tt>char</tt>, <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and
     * <tt>double</tt>.
     *
     * <p> View buffers have three important advantages over the families of
     * type-specific <i>get</i> and <i>put</i> methods described above:
     *
     * <ul>
     *
     * <li><p> A view buffer is indexed not in terms of bytes but rather in terms
     * of the type-specific size of its values;  </p></li>
     *
     * <li><p> A view buffer provides relative bulk <i>get</i> and <i>put</i>
     * methods that can transfer contiguous sequences of values between a buffer
     * and an array or some other buffer of the same type; and  </p></li>
     *
     * <li><p> A view buffer is potentially much more efficient because it will
     * be direct if, and only if, its backing byte buffer is direct.  </p></li>
     *
     * </ul>
     *
     * <p> The byte order of a view buffer is fixed to be that of its byte buffer
     * at the time that the view is created.  </p>
     *
     *
     * <h2> Invocation chaining </h2>
     *
     *
     * <p> Methods in this class that do not otherwise have a value to return are
     * specified to return the buffer upon which they are invoked.  This allows
     * method invocations to be chained.
     * <p>
     * <p>
     * <p>
     * The sequence of statements
     *
     * <blockquote><pre>
     * bb.putInt(0xCAFEBABE);
     * bb.putShort(3);
     * bb.putShort(45);</pre></blockquote>
     * <p>
     * can, for example, be replaced by the single statement
     *
     * <blockquote><pre>
     * bb.putInt(0xCAFEBABE).putShort(3).putShort(45);</pre></blockquote>
     *
     * @author Mark Reinhold
     * @author JSR-51 Expert Group
     * @since 1.4
     */
    
    public abstract class ByteBuffer
            extends Buffer
            implements Comparable<ByteBuffer> {
    
        //这些字段在此声明,而不是在Heap-X-Buffer中声明
        //减少访问这些调用所需的虚拟方法调用次数
        //值,编码小缓冲区时成本特别高.
    
        /**
         * 通过源码我们可以清楚的知道ByteBuffer底层其实就是一个比byte数组
         */
        final byte[] hb;                  // 仅对堆缓冲区为非null
        final int offset;
        boolean isReadOnly;                 //仅对堆缓冲区有效
    
        //创建一个具有给定标记,位置,限制,容量的新缓冲区
        //后备数组和数组偏移量
        //
        ByteBuffer(int mark, int pos, int lim, int cap,
                   byte[] hb, int offset) {
            /**
             * 这里调用了java.nio.Buffer四个参数的构造方法,说明
             * private int mark = -1;
             * private int position = 0;
             * private int limit;
             * private int capacity;
             * 都是父类的属性
             */
            super(mark, pos, lim, cap);
            this.hb = hb;
            this.offset = offset;
        }
    
        // 使用给定的标记,位置,限制和容量创建新缓冲区
    
        ByteBuffer(int mark, int pos, int lim, int cap) {
            this(mark, pos, lim, cap, null, 0);
        }
    
    
        /**
         * 分配新的直接字节缓冲区。
         * <p>
         * 新缓冲区的位置将为零,其限制将为其
         * 容量,其标记将是未定义的,其每个元素都将是
         * 初始化为零。是否有
         * {@link #hasArray支持数组}未指定。
         *
         * @param capacity 新缓冲区的容量,以字节为单位
         * @return 新的字节缓冲区
         * @throws IllegalArgumentException 如果capacity 是负整数
         *                                  <p>
         *                                  这里要注意的是直接缓冲区的意义,这个方法申请的空间不是在JVM堆中,
         *                                  而是在JVM堆外操作系统的内存中获取空间,
         *                                  省去了拷贝的开销
         */
        public static ByteBuffer allocateDirect(int capacity) {
            return new DirectByteBuffer(capacity);
        }
    
    
        /**
         * 分配一个新的字节缓冲区。
         * <p>
         * 新缓冲区的位置将为零,其限制将为其
         * 容量,其标记将是未定义的,其每个元素都将是
         * 初始化为零。它将有一个{@link #array支持数组},
         * 及其{@link #arrayOffset数组偏移}将为零。
         *
         * @param capacity 新缓冲区的容量,以字节为单位
         * @return 新的字节缓冲区
         * @throws IllegalArgumentException 如果容量是负整数
         */
        public static ByteBuffer allocate(int capacity) {
            if (capacity < 0)
                throw new IllegalArgumentException();
            /**
             * 在JVM堆中获取空间
             * java.nio.HeapByteBuffer
             */
            return new HeapByteBuffer(capacity, capacity);
        }
    
        /**
         * 将字节数组包装到缓冲区中。
         * <p>
         * 新缓冲区将由给定的字节数组支持;
         * 也就是说,对缓冲区的修改将导致数组被修改
         * 反之亦然。新缓冲区的容量将是
         * array.length ,其位置将offset,其限制
         * 将是offset + length ,其标记将是未定义的。它的
         * {@link #array backing array}将是给定的数组,和
         * 它的{@link #arrayOffset数组偏移}将为零。
         *
         * @param array  将支持新缓冲区的数组
         * @param offset 要使用的子阵列的偏移量;必须是非负的
         *               不大于array.length 。新缓冲区的位置
         *               将被设置为此值。
         * @param length 要使用的子阵列的长度;
         *               必须是非负的且不大于
         *               array.length - offset
         *               新缓冲区的限制将设置为offset + length 。
         * @return 新的字节缓冲区
         * @throws IndexOutOfBoundsException 如果偏移和长度的先决条件
         *                                   参数不成立
         */
    
    
        public static ByteBuffer wrap(byte[] array,
                                      int offset, int length) {
            try {
                return new HeapByteBuffer(array, offset, length);
            } catch (IllegalArgumentException x) {
                throw new IndexOutOfBoundsException();
            }
        }
    
        /**
         * 将字节数组包装到缓冲区中。
         */
    
        public static ByteBuffer wrap(byte[] array) {
            return wrap(array, 0, array.length);
        }
    
    
        /**
         * 创建一个新的字节缓冲区,其内容是共享的子序列
         * 此缓冲区的内容。
         * <p>
         * 新缓冲区的内容将从此缓冲区的当前开始
         * 位置。此缓冲区内容的更改将在新的中显示
         * 缓冲区,反之亦然;两个缓冲区的位置,限制和标记
         * 值将是独立的。
         * <p>
         * 新缓冲区的位置将为零,其容量和限制
         * 将是此缓冲区中剩余的字节数及其标记
         * 将是未定义的。当且仅当这个时,新缓冲区将是直接的
         * 缓冲区是直接的,只有当这个缓冲区时它才是只读的
         * 是只读的。
         *
         * @return The new byte buffer
         * <p>
         * ByteBuffer的子类HeapByteBuffer对该方法的实现
         * public ByteBuffer slice() {
         * return new HeapByteBuffer(hb,-1,0,this.remaining(),this.remaining(),this.position() + offset);
         * }
         */
        public abstract ByteBuffer slice();
    
        /**
         * 创建一个共享此缓冲区内容的新字节缓冲区。
         * <p>
         * 新缓冲区的内容将是此缓冲区的内容。变化
         * 此缓冲区的内容将在新缓冲区中显示,反之亦然;
         * 两个缓冲区的位置,限制和标记值将是
         * 独立。
         * <p>
         * 新缓冲区的容量,限制,位置和标记值将是
         * 与此缓冲区的相同。如果,新的缓冲区将是直接的,
         * 且仅当此缓冲区是直接的时,如果和,它将是只读的
         * 仅当此缓冲区为只读时。
         * <p>
         * ByteBuffer的子类HeapByteBuffer对该方法的实现
         * public ByteBuffer duplicate() {
         * return new HeapByteBuffer(hb,this.markValue(),this.position(),this.limit(),this.capacity(),offset);
         * }
         * <p>
         * HeapByteBuffer(byte[] buf,int mark, int pos, int lim, int cap,int off)
         */
        public abstract ByteBuffer duplicate();
    
        /**
         * 创建一个共享此缓冲区的新的只读字节缓冲区
         * 内容。
         * <p>
         * ByteBuffer的子类HeapByteBuffer对该方法的实现
         * <p>
         * public ByteBuffer asReadOnlyBuffer() {
         * return new HeapByteBufferR(hb,this.markValue(),this.position(),this.limit(),this.capacity(),offset);
         * }
         * <p>
         * HeapByteBufferR 是HeapByteBuffer的子类,内部将HeapByteBuffer的this.isReadOnly 属性设置为 true;
         */
        public abstract ByteBuffer asReadOnlyBuffer();
    
    
        // -- Singleton get / put方法 --
    
        /**
         * 相对 get 方法。读取此缓冲区的字节
         * 当前位置,然后增加位置。
         *
         * @return 缓冲区当前位置的字节
         * @throws BufferUnderflowException 如果缓冲区的当前位置不大于其限制抛出该异常
         *                                  <p>
         *  在HeapByteBuffer中对该方法的实现
         *                                  public byte get() {
         *                                  return hb[ix(nextGetIndex())];
         *                                  }
         *                                  final int nextGetIndex() {                         
         *                                  if (position >= limit)
         *                                  throw new BufferUnderflowException();
         *                                  return position++;
         *                                  }
         */
        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);
    
    
        // -- 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>
         * <p>
         * 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;
        }
    
        /**
         * Relative bulk <i>get</i> method.
         *
         * <p> This method transfers bytes from this buffer into the given
         * destination array.  An invocation of this method of the form
         * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
         *
         * <pre>
         *     src.get(a, 0, a.length) </pre>
         *
         * @param dst The destination array
         * @return This buffer
         * @throws BufferUnderflowException If there are fewer than <tt>length</tt> bytes
         *                                  remaining in this buffer
         */
        public ByteBuffer get(byte[] dst) {
            return get(dst, 0, dst.length);
        }
    
    
        // -- 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>
         * <p>
         * 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;
        }
    
        /**
         * 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>
         * <p>
         * 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;
        }
    
        /**
         * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> This method transfers the entire content of the given source
         * byte array into this buffer.  An invocation of this method of the
         * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
         * invocation
         *
         * <pre>
         *     dst.put(a, 0, a.length) </pre>
         *
         * @param src The source array
         * @return This buffer
         * @throws BufferOverflowException If there is insufficient space in this buffer
         * @throws ReadOnlyBufferException If this buffer is read-only
         */
        public final ByteBuffer put(byte[] src) {
            return put(src, 0, src.length);
        }
    
    
        // -- Other stuff --
    
        /**
         * Tells whether or not this buffer is backed by an accessible byte
         * array.
         *
         * <p> If this method returns <tt>true</tt> then the {@link #array() array}
         * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
         * </p>
         *
         * @return <tt>true</tt> if, and only if, this buffer
         * is backed by an array and is not read-only
         */
        public final boolean hasArray() {
            return (hb != null) && !isReadOnly;
        }
    
        /**
         * Returns the byte array that backs this
         * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Modifications to this buffer's content will cause the returned
         * array's content to be modified, and vice versa.
         *
         * <p> Invoke the {@link #hasArray hasArray} method before invoking this
         * method in order to ensure that this buffer has an accessible backing
         * array.  </p>
         *
         * @return The array that backs this buffer
         * @throws ReadOnlyBufferException       If this buffer is backed by an array but is read-only
         * @throws UnsupportedOperationException If this buffer is not backed by an accessible array
         */
        public final byte[] array() {
            if (hb == null)
                throw new UnsupportedOperationException();
            if (isReadOnly)
                throw new ReadOnlyBufferException();
            return hb;
        }
    
        /**
         * Returns the offset within this buffer's backing array of the first
         * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> If this buffer is backed by an array then buffer position <i>p</i>
         * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
         *
         * <p> Invoke the {@link #hasArray hasArray} method before invoking this
         * method in order to ensure that this buffer has an accessible backing
         * array.  </p>
         *
         * @return The offset within this buffer's array
         * of the first element of the buffer
         * @throws ReadOnlyBufferException       If this buffer is backed by an array but is read-only
         * @throws UnsupportedOperationException If this buffer is not backed by an accessible array
         */
        public final int arrayOffset() {
            if (hb == null)
                throw new UnsupportedOperationException();
            if (isReadOnly)
                throw new ReadOnlyBufferException();
            return offset;
        }
    
        /**
         * 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();
    
        /**
         * Tells whether or not this byte buffer is direct.
         *
         * @return <tt>true</tt> if, and only if, this buffer is direct
         */
        public abstract boolean isDirect();
    
    
        /**
         * Returns a string summarizing the state of this buffer.
         *
         * @return A summary string
         */
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append(getClass().getName());
            sb.append("[pos=");
            sb.append(position());
            sb.append(" lim=");
            sb.append(limit());
            sb.append(" cap=");
            sb.append(capacity());
            sb.append("]");
            return sb.toString();
        }
    
    
        /**
         * Returns the current hash code of this buffer.
         *
         * <p> The hash code of a byte buffer depends only upon its remaining
         * elements; that is, upon the elements from <tt>position()</tt> up to, and
         * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
         *
         * <p> Because buffer hash codes are content-dependent, it is inadvisable
         * to use buffers as keys in hash maps or similar data structures unless it
         * is known that their contents will not change.  </p>
         *
         * @return The current hash code of this buffer
         */
        public int hashCode() {
            int h = 1;
            int p = position();
            for (int i = limit() - 1; i >= p; i--)
                h = 31 * h + (int) get(i);
    
            return h;
        }
    
        /**
         * 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;
        }
    
        private static boolean equals(byte x, byte y) {
            return x == y;
        }
    
        /**
         * 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.
         * <p>
         * 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();
        }
    
        private static int compare(byte x, byte y) {
            return Byte.compare(x, y);
        }
    
        // -- Other char stuff --
    
    
        // -- Other byte stuff: Access to binary data --
    
    
        boolean bigEndian  = true;
        boolean nativeByteOrder = (Bits.byteOrder() == ByteOrder.BIG_ENDIAN);
    
        /**
         * Retrieves this buffer's byte order.
         *
         * <p> The byte order is used when reading or writing multibyte values, and
         * when creating buffers that are views of this byte buffer.  The order of
         * a newly-created byte buffer is always {@link ByteOrder#BIG_ENDIAN
         * BIG_ENDIAN}.  </p>
         *
         * @return This buffer's byte order
         */
        public final ByteOrder order() {
            return bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
        }
    
        /**
         * Modifies this buffer's byte order.
         *
         * @param bo The new byte order,
         *           either {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}
         *           or {@link ByteOrder#LITTLE_ENDIAN LITTLE_ENDIAN}
         * @return This buffer
         */
        public final ByteBuffer order(ByteOrder bo) {
            bigEndian = (bo == ByteOrder.BIG_ENDIAN);
            nativeByteOrder =
                    (bigEndian == (Bits.byteOrder() == ByteOrder.BIG_ENDIAN));
            return this;
        }
    
        // Unchecked accessors, for use by ByteBufferAs-X-Buffer classes
        //
        abstract byte _get(int i);                          // package-private
    
        abstract void _put(int i, byte b);                  // package-private
    
    
        /**
         * Relative <i>get</i> method for reading a char value.
         *
         * <p> Reads the next two bytes at this buffer's current position,
         * composing them into a char value according to the current byte order,
         * and then increments the position by two.  </p>
         *
         * @return The char value at the buffer's current position
         * @throws BufferUnderflowException If there are fewer than two bytes
         *                                  remaining in this buffer
         */
        public abstract char getChar();
    
        /**
         * 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);
    
        /**
         * Absolute <i>get</i> method for reading a char value.
         *
         * <p> Reads two bytes at the given index, composing them into a
         * char value according to the current byte order.  </p>
         *
         * @param index The index from which the bytes will be read
         * @return The char value at the given index
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus one
         */
        public abstract char getChar(int index);
    
        /**
         * Absolute <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 given index.  </p>
         *
         * @param index The index at which the bytes will be written
         * @param value The char value to be written
         * @return This buffer
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus one
         * @throws ReadOnlyBufferException   If this buffer is read-only
         */
        public abstract ByteBuffer putChar(int index, char value);
    
        /**
         * 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();
    
    
        /**
         * Relative <i>get</i> method for reading a short value.
         *
         * <p> Reads the next two bytes at this buffer's current position,
         * composing them into a short value according to the current byte order,
         * and then increments the position by two.  </p>
         *
         * @return The short value at the buffer's current position
         * @throws BufferUnderflowException If there are fewer than two bytes
         *                                  remaining in this buffer
         */
        public abstract short getShort();
    
        /**
         * Relative <i>put</i> method for writing a short
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes two bytes containing the given short value, in the
         * current byte order, into this buffer at the current position, and then
         * increments the position by two.  </p>
         *
         * @param value The short 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 putShort(short value);
    
        /**
         * Absolute <i>get</i> method for reading a short value.
         *
         * <p> Reads two bytes at the given index, composing them into a
         * short value according to the current byte order.  </p>
         *
         * @param index The index from which the bytes will be read
         * @return The short value at the given index
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus one
         */
        public abstract short getShort(int index);
    
        /**
         * Absolute <i>put</i> method for writing a short
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes two bytes containing the given short value, in the
         * current byte order, into this buffer at the given index.  </p>
         *
         * @param index The index at which the bytes will be written
         * @param value The short value to be written
         * @return This buffer
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus one
         * @throws ReadOnlyBufferException   If this buffer is read-only
         */
        public abstract ByteBuffer putShort(int index, short value);
    
        /**
         * Creates a view of this byte buffer as a short 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 short buffer
         */
        public abstract ShortBuffer asShortBuffer();
    
    
        /**
         * Relative <i>get</i> method for reading an int value.
         *
         * <p> Reads the next four bytes at this buffer's current position,
         * composing them into an int value according to the current byte order,
         * and then increments the position by four.  </p>
         *
         * @return The int value at the buffer's current position
         * @throws BufferUnderflowException If there are fewer than four bytes
         *                                  remaining in this buffer
         */
        public abstract int getInt();
    
        /**
         * Relative <i>put</i> method for writing an int
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes four bytes containing the given int value, in the
         * current byte order, into this buffer at the current position, and then
         * increments the position by four.  </p>
         *
         * @param value The int value to be written
         * @return This buffer
         * @throws BufferOverflowException If there are fewer than four bytes
         *                                 remaining in this buffer
         * @throws ReadOnlyBufferException If this buffer is read-only
         */
        public abstract ByteBuffer putInt(int value);
    
        /**
         * Absolute <i>get</i> method for reading an int value.
         *
         * <p> Reads four bytes at the given index, composing them into a
         * int value according to the current byte order.  </p>
         *
         * @param index The index from which the bytes will be read
         * @return The int value at the given index
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus three
         */
        public abstract int getInt(int index);
    
        /**
         * Absolute <i>put</i> method for writing an int
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes four bytes containing the given int value, in the
         * current byte order, into this buffer at the given index.  </p>
         *
         * @param index The index at which the bytes will be written
         * @param value The int value to be written
         * @return This buffer
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus three
         * @throws ReadOnlyBufferException   If this buffer is read-only
         */
        public abstract ByteBuffer putInt(int index, int value);
    
        /**
         * Creates a view of this byte buffer as an int 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
         * four, 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 int buffer
         */
        public abstract IntBuffer asIntBuffer();
    
    
        /**
         * Relative <i>get</i> method for reading a long value.
         *
         * <p> Reads the next eight bytes at this buffer's current position,
         * composing them into a long value according to the current byte order,
         * and then increments the position by eight.  </p>
         *
         * @return The long value at the buffer's current position
         * @throws BufferUnderflowException If there are fewer than eight bytes
         *                                  remaining in this buffer
         */
        public abstract long getLong();
    
        /**
         * Relative <i>put</i> method for writing a long
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes eight bytes containing the given long value, in the
         * current byte order, into this buffer at the current position, and then
         * increments the position by eight.  </p>
         *
         * @param value The long value to be written
         * @return This buffer
         * @throws BufferOverflowException If there are fewer than eight bytes
         *                                 remaining in this buffer
         * @throws ReadOnlyBufferException If this buffer is read-only
         */
        public abstract ByteBuffer putLong(long value);
    
        /**
         * Absolute <i>get</i> method for reading a long value.
         *
         * <p> Reads eight bytes at the given index, composing them into a
         * long value according to the current byte order.  </p>
         *
         * @param index The index from which the bytes will be read
         * @return The long value at the given index
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus seven
         */
        public abstract long getLong(int index);
    
        /**
         * Absolute <i>put</i> method for writing a long
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes eight bytes containing the given long value, in the
         * current byte order, into this buffer at the given index.  </p>
         *
         * @param index The index at which the bytes will be written
         * @param value The long value to be written
         * @return This buffer
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus seven
         * @throws ReadOnlyBufferException   If this buffer is read-only
         */
        public abstract ByteBuffer putLong(int index, long value);
    
        /**
         * Creates a view of this byte buffer as a long 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
         * eight, 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 long buffer
         */
        public abstract LongBuffer asLongBuffer();
    
    
        /**
         * Relative <i>get</i> method for reading a float value.
         *
         * <p> Reads the next four bytes at this buffer's current position,
         * composing them into a float value according to the current byte order,
         * and then increments the position by four.  </p>
         *
         * @return The float value at the buffer's current position
         * @throws BufferUnderflowException If there are fewer than four bytes
         *                                  remaining in this buffer
         */
        public abstract float getFloat();
    
        /**
         * Relative <i>put</i> method for writing a float
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes four bytes containing the given float value, in the
         * current byte order, into this buffer at the current position, and then
         * increments the position by four.  </p>
         *
         * @param value The float value to be written
         * @return This buffer
         * @throws BufferOverflowException If there are fewer than four bytes
         *                                 remaining in this buffer
         * @throws ReadOnlyBufferException If this buffer is read-only
         */
        public abstract ByteBuffer putFloat(float value);
    
        /**
         * Absolute <i>get</i> method for reading a float value.
         *
         * <p> Reads four bytes at the given index, composing them into a
         * float value according to the current byte order.  </p>
         *
         * @param index The index from which the bytes will be read
         * @return The float value at the given index
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus three
         */
        public abstract float getFloat(int index);
    
        /**
         * Absolute <i>put</i> method for writing a float
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes four bytes containing the given float value, in the
         * current byte order, into this buffer at the given index.  </p>
         *
         * @param index The index at which the bytes will be written
         * @param value The float value to be written
         * @return This buffer
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus three
         * @throws ReadOnlyBufferException   If this buffer is read-only
         */
        public abstract ByteBuffer putFloat(int index, float value);
    
        /**
         * Creates a view of this byte buffer as a float 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
         * four, 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 float buffer
         */
        public abstract FloatBuffer asFloatBuffer();
    
    
        /**
         * Relative <i>get</i> method for reading a double value.
         *
         * <p> Reads the next eight bytes at this buffer's current position,
         * composing them into a double value according to the current byte order,
         * and then increments the position by eight.  </p>
         *
         * @return The double value at the buffer's current position
         * @throws BufferUnderflowException If there are fewer than eight bytes
         *                                  remaining in this buffer
         */
        public abstract double getDouble();
    
        /**
         * Relative <i>put</i> method for writing a double
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes eight bytes containing the given double value, in the
         * current byte order, into this buffer at the current position, and then
         * increments the position by eight.  </p>
         *
         * @param value The double value to be written
         * @return This buffer
         * @throws BufferOverflowException If there are fewer than eight bytes
         *                                 remaining in this buffer
         * @throws ReadOnlyBufferException If this buffer is read-only
         */
        public abstract ByteBuffer putDouble(double value);
    
        /**
         * Absolute <i>get</i> method for reading a double value.
         *
         * <p> Reads eight bytes at the given index, composing them into a
         * double value according to the current byte order.  </p>
         *
         * @param index The index from which the bytes will be read
         * @return The double value at the given index
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus seven
         */
        public abstract double getDouble(int index);
    
        /**
         * Absolute <i>put</i> method for writing a double
         * value&nbsp;&nbsp;<i>(optional operation)</i>.
         *
         * <p> Writes eight bytes containing the given double value, in the
         * current byte order, into this buffer at the given index.  </p>
         *
         * @param index The index at which the bytes will be written
         * @param value The double value to be written
         * @return This buffer
         * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
         *                                   or not smaller than the buffer's limit,
         *                                   minus seven
         * @throws ReadOnlyBufferException   If this buffer is read-only
         */
        public abstract ByteBuffer putDouble(int index, double value);
    
        /**
         * Creates a view of this byte buffer as a double 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
         * eight, 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 double buffer
         */
        public abstract DoubleBuffer asDoubleBuffer();
    
    }
    

    相关文章

      网友评论

          本文标题:java.nio.ByteBuffer源码

          本文链接:https://www.haomeiwen.com/subject/meenxctx.html