zoukankan      html  css  js  c++  java
  • 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魔术类的方法, 在此就不做衍生了, 有兴趣的自己去撸源码。

  • 相关阅读:
    A Node Influence Based Label Propagation Algorithm for Community detection in networks 文章算法实现的疑问
    Fast Newman-FN算法以及模块度定义介绍
    Label Propagation Algorithm LPA 标签传播算法解析及matlab代码实现
    设计一个smartnic
    Intel GEN11 GPU
    Intel GEN9 GPU
    Shared Virtual Memory (SVM) Functions
    connect via ssh to virtualbox guest vm without knowing ip address
    smartnic
    技术精品翻译
  • 原文地址:https://www.cnblogs.com/ronnieyuan/p/11996640.html
Copyright © 2011-2022 走看看