NIO 组件Buffer

重要属性

属性 描述
Capacity 容量, 即可以容纳的最大数据量; 在缓冲区创建时被设定并且不能改变
Limit 表示缓冲区的当前终点, 不能对缓冲区超过极限的位置进行读写操作, 且极限是可以修改的。
Position 位置, 下一个要被读或写的元素的索引, 每次读写缓冲区数据时都会改变数值, 为下次读写做准备
Mark 标记

简单demo

  • 代码:
package com.ronnie.nio;

import java.nio.IntBuffer;

public class BasicBuffer {
    public static void main(String[] args) {

        // 举例说明Buffer 的使用
        // 创建一个Buffer, 大小为n, 即可存放n个int

        IntBuffer intBuffer = IntBuffer.allocate(10);

        // 向buffer 存放数据
        for (int i = 0; i < intBuffer.capacity(); i++){
            intBuffer.put( i * 2);
        }

        // 将buffer转换, 读写切换(很重要)
        intBuffer.flip();

        intBuffer.position(1);
        // 设置limit为3, 到不了3
        intBuffer.limit(3);
        while (intBuffer.hasRemaining()){
            System.out.println(intBuffer.get());
        }
    }
  • 输出结果: 2 4
  • 感觉这个思想和golang里面的channel好像差不多, 不过go的channel好像并不需要flip, 若不指定方向就是双向的。

源码解读

  • 属性

        /**
         * The characteristics of Spliterators that traverse and split elements
         * maintained in Buffers.
         * Spliterators 是一个可分割迭代器, 此处用于遍历并分割Buffer中的元素, 此类有三种
         * 特征的Spliterators: 尺寸固定的, 小尺寸的, 有序的三种, 进去看一下都是16进制数 
         */
        static final int SPLITERATOR_CHARACTERISTICS =
            Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
    
        // Invariants: mark <= position <= limit <= capacity 不变性排序
        private int mark = -1;
        private int position = 0;
        private int limit;
        private int capacity;
    
        // Used only by direct buffers 只能直接被buffers使用
        // NOTE: hoisted here for speed in JNI GetDirectBufferAddress
        // 挂在这用于提升 JNI(Java Native Interface) 中直接获取buffer地址方法的执行速度
        long address;
    
  • 常用方法

    • public final int capacity(){}: 返回此缓冲区的容量

       /**
           * Returns this buffer's capacity.
           *
           * @return  The capacity of this buffer
           */
          public final int capacity() {
              return capacity;
          }
      
    • public final int position(){}: 返回此缓冲区的位置

      /**
           * Returns this buffer's position.
           *
           * @return  The position of this buffer
           */
          public final int position() {
              return position;
          }
      
      
    • public final Buffer position(int newPosition){}: 设置此缓冲区的位置

          /**
           * Sets this buffer's position.  If the mark is defined and larger than 
           * the new position then it is discarded.
           * 设置该buffer的位置, 如果此标记已经被定义, 且大于新定义的位置, 那么它就会被
           * 抛弃。
           *
           * @param  newPosition
           *         The new position value; must be non-negative
           *         and no larger than the current limit
           *
           * @return  This buffer
           *
           * @throws  IllegalArgumentException
           *          If the preconditions on <tt>newPosition</tt> do not hold
           */
          public final Buffer position(int newPosition) {
              if ((newPosition > limit) || (newPosition < 0))
                  throw new IllegalArgumentException();
              position = newPosition;
              if (mark > position) mark = -1;
              return this;
          }
      
    • public final int limit(){}: 返回此缓冲区的限制

        /**
           * Returns this buffer's limit.
           *
           * @return  The limit of this buffer
           */
          public final int limit() {
              return limit;
          }
      
    • public final Buffer limit(int newLimit){}: 设置此缓冲区的限制

       /**
           * Sets this buffer's limit.  
           * If the position is larger than the new limit then it is set to the new 
           * limit.  
           * 如果位置大于新的limit, 那么就将位置设为新的limit
           * If the mark is defined and larger than the new limit then it is 
           * discarded.
           * 如果此标记已经被定义, 且大于新定义的位置, 那么它就会被抛弃。
           *
           * @param  newLimit
           *         The new limit value; must be non-negative
           *         and no larger than this buffer's capacity
           *
           * @return  This buffer
           *
           * @throws  IllegalArgumentException
           *          If the preconditions on <tt>newLimit</tt> do not hold
           */
          public final Buffer limit(int newLimit) {
              if ((newLimit > capacity) || (newLimit < 0))
                  throw new IllegalArgumentException();
              limit = newLimit;
              if (position > limit) position = limit;
              if (mark > limit) mark = -1;
              return this;
          }
      
    • public final Buffer clear(){}: 清除此缓冲区, 即将各个标记恢复到初始状态, 但是数据并没有真正擦除

          /**
           * Clears this buffer.  
           * The position is set to zero, the limit is set to the capacity, and the 
           * mark is discarded.
           * 位置被设为0, limit被设置为容量, 并且标记被丢弃。
           *
           * <p> Invoke this method before using a sequence of channel-read or
           * <i>put</i> operations to fill this buffer.  For example:
           *
           * <blockquote><pre>
           * buf.clear();     // Prepare buffer for reading
           * in.read(buf);    // Read data</pre></blockquote>
           *
           * <p> This method does not actually erase the data in the buffer, but it
           * is named as if it did because it will most often be used in situations
           * in which that might as well be the case. </p>
           *
           * @return  This buffer
           */
          public final Buffer clear() {
              position = 0;
              limit = capacity;
              mark = -1;
              return this;
          }
      
    • public abstract boolean hasArray(){}: 告知此缓冲区是否具有可访问的底层实现数组

       /**
           * Tells whether or not this buffer is backed by an accessible
           * 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
           *
           * @since 1.6
           */
          public abstract boolean hasArray();
      
    • public abstract Object array(){}: 返回此缓冲区的底层实现数组

       /**
           * Returns the array that backs this
           * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
           *
           * <p> This method is intended to allow array-backed buffers to be
           * passed to native code more efficiently. 
           * 该方法的目的是允许 底层的 实现数组缓冲区 更有效地被传送到本地编码中。
           * Concrete subclasses provide more strongly-typed return values for this 
           * method.
           * 实体的子类为该方法提供了更多强类型的返回值
           *
           * <p> Modifications to this buffer's content will cause the returned
           * array's content to be modified, and vice versa.
           * 修改该buffer的内容会导致返回的数组的内容也被改变, 反之亦然。
           *
           * <p> Invoke the {@link #hasArray hasArray} method before invoking this
           * method in order to ensure that this buffer has an accessible backing
           * array.  </p>
           * 在调用此方法前请调用hasArray方法来保证该buffer有一个可获取的底层实现数组
           *
           * @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
           *
           * @since 1.6
           */
          public abstract Object array();
      
      
  • 其他方法

    • public final Buffer mark(){}: 在此缓冲区的位置设置标记

       /**
           * Sets this buffer's mark at its position.
           *
           * @return  This buffer
           */
          public final Buffer mark() {
              mark = position;
              return this;
          }
      
    • public final Buffer reset(){}: 将此缓冲区的位置重置为以前标记的位置(后悔药?)

       /**
           * Resets this buffer's position to the previously-marked position.
           *
           * <p> Invoking this method neither changes nor discards the mark's
           * value. </p>
           *
           * @return  This buffer
           *
           * @throws  InvalidMarkException
           *          If the mark has not been set
           */
          public final Buffer reset() {
              int m = mark;
              if (m < 0)
                  throw new InvalidMarkException();
              // 将位置设为之前的标记
              position = m;
              return this;
          }
      
    • public final Buffer rewind(){}: 重绕此缓冲区

          /**
           * Rewinds this buffer. 
           * The position is set to zero and the mark is discarded.
           * 位置被设为0并且标记被丢弃
           *
           * <p> Invoke this method before a sequence of channel-write or <i>get</i>
           * operations, assuming that the limit has already been set
           * appropriately.  For example:
           *
           * <blockquote><pre>
           * out.write(buf);    // Write remaining data
           * buf.rewind();      // Rewind buffer
           * buf.get(array);    // Copy data into array</pre></blockquote>
           *
           * @return  This buffer
           */
          public final Buffer rewind() {
              position = 0;
              mark = -1;
              return this;
          }
      
    • public final int remaining(){}: 返回当前位置与限制之间的元素数量

      
          /**
           * Returns the number of elements between the current position and the
           * limit.
           *
           * @return  The number of elements remaining in this buffer
           */
          public final int remaining() {
              return limit - position;
          }
      
    • public abstract int arrayOffset(){}: 返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量

       /**
           * 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>
           *  在调用此方法前请调用hasArray方法来保证该buffer有一个可获取的底层实现数组
           *
           * @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
           *
           * @since 1.6
           */
          public abstract int arrayOffset();
      
    • public abstract boolean isDirect(){}: 告知此缓冲区是否为直接缓冲区

          /**
           * Tells whether or not this buffer is
           * <a href="ByteBuffer.html#direct"><i>direct</i></a>.
           *
           * @return  <tt>true</tt> if, and only if, this buffer is direct
           *
           * @since 1.6
           */
          public abstract boolean isDirect();
      

ByteBuffer

  • 是最常用的ByteBuffer类(二进制数组)

  • 常用方法:

    • 缓冲区创建相关:

      • public static ByteBuffer allocateDirect(int capacity){}: 创建直接缓冲区

            /**
             * 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.  
             * 新缓冲区的位置将会为0, 它的limit会是它的容量, 它的标签未被定义, 每个它
             * 元素都会被定义为0.
             * 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);
            }
        
      • public static ByteBuffer allocate(int 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.  
             * 新缓冲区的位置将会为0, 它的limit会是它的容量, 它的标签未被定义, 每个它
             * 元素都会被定义为0.
             * It will have a {@link #array backing array},and its {@link 
             * #arrayOffset array offset} will be zero.
             * 它会有一个底层数组, 并且它的数组偏移量为0
             *
             * @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);
            }
        
    • 缓存区存取相关:

      • public abstract byte get(){}: 从当前位置position上get, get之后, position会自动+1

            // -- Singleton get/put methods -- get/put 都是操作单例对象的
        
            /**
             * Relative <i>get</i> method.  
             * Reads the byte at this buffer's current position, and then 
             * increments the position.
             * 读该字节数组在此buffer的当前位置, 并提升位置 
             *
             * @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();
        
      • public abstract byte get(int index){}: 从绝对位置get, position不会自动+1

         /**
             * 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);
        
      • public abstract ByteBuffer put(byte b){}: 从当前位置上添加, put之后, position会自动 +1

            /**
             * 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>
             * 将获取的字节数组写入到该buffer中的当前位置, 并将位置上升
             *
             * @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);
        
        
      • public abstract ByteBuffer put(int index, byte b){}: 从绝对位置上put, position不会自动+1

        /**
             * 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);
        
      • 咦, 咋么都是抽象方法呐, 自习看一下层级结构:

        1575624399783

      • 稍微看了一下, 它们的实现类在HeapByteBuffer和DirectByteBuffer中, 后者还调用了sun.misc.unsafe魔术类的方法, 在此就不做衍生了, 有兴趣的自己去撸源码。

posted @ 2019-12-06 17:33  wellDoneGaben  阅读(165)  评论(0编辑  收藏  举报