zoukankan      html  css  js  c++  java
  • Java NIO —— Buffer(缓冲区)

    Buffer是一个抽象类,位于java.nio包中,主要用作缓冲区。注意:Buffer是非线程安全类。

    缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。

    NIO 有以下几种Buffer类型:

    • ByteBuffer
    • MappedByteBuffer
    • CharBuffer
    • DoubleBuffer
    • FloatBuffer
    • IntBuffer
    • LongBuffer
    • ShortBuffer

    capacity

    作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

    capacity一旦初始化 
    后就不会改变,其值一直为常量。在使用中我们一般使用Buffer的抽象子类ByteBuffer.allocate()方法,实际上是生成ByteArrayBuffer类。

    position

    当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1。

    当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0。当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

    limit

    在读模式下,Buffer的limit表示你最多能从Buffer里读多少数据。 写模式下,limit等于Buffer的capacity。

    当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

    (1)Buffer中定义的变量含义

    /**
     * <code>UNSET_MARK</code> means the mark has not been set.
     */
    static final int UNSET_MARK = -1;
    
    /**
     * The capacity of this buffer, which never changes.
     */
    final int capacity;
    
    /**
     * <code>limit - 1</code> is the last element that can be read or written.
     * Limit must be no less than zero and no greater than <code>capacity</code>.
     */
    int limit;
    
    /**
     * Mark is where position will be set when <code>reset()</code> is called.
     * Mark is not set by default. Mark is always no less than zero and no
     * greater than <code>position</code>.
     */
    int mark = UNSET_MARK;
    
    /**
     * The current position of this buffer. Position is always no less than zero
     * and no greater than <code>limit</code>.
     */
    int position = 0;
    
    /**
     * The log base 2 of the element size of this buffer.  Each typed subclass
     * (ByteBuffer, CharBuffer, etc.) is responsible for initializing this
     * value.  The value is used by JNI code in frameworks/base/ to avoid the
     * need for costly 'instanceof' tests.
     */
    final int _elementSizeShift;
    
    /**
     * For direct buffers, the effective address of the data; zero otherwise.
     * This is set in the constructor.
     */
    final long effectiveDirectAddress;

    (2)clear()方法用于写模式,其作用为清空Buffer中的内容,所谓清空是指写上限与Buffer的真实容量相同,即limit==capacity,同时将当前写位置置为最前端下标为0处。代码如下:

    /**
     * <code>UNSET_MARK</code> means the mark has not been set.
     */
    static final int UNSET_MARK = -1;
    
    /**
     * Clears this buffer.
     * <p>
     * While the content of this buffer is not changed, the following internal
     * changes take place: the current position is reset back to the start of
     * the buffer, the value of the buffer limit is made equal to the capacity
     * and mark is cleared.
     *
     * @return this buffer.
     */
    public final Buffer clear() {
        position = 0; //设置当前下标为0 
        mark = UNSET_MARK; //取消标记 
        limit = capacity; //设置写越界位置与和Buffer容量相同  
        return this;
    }

    (3)reset()方法和clear()方法一样用于写模式,区别是reset()的作用是丢弃mark位置以后的数据,重新从mark位置开始写入,且mark不能未设置;而clear是从0位置开始重新写入。

    • /**
       * Sets this buffer's mark at its position.
       *
       * @return  This buffer
       */
      public final Buffer mark() {
          mark = position;
          return this;
      }
      
      /**
       * Resets the position of this buffer to the <code>mark</code>.
       *
       * @return this buffer.
       * @throws InvalidMarkException
       *                if the mark is not set.
       */
      public final Buffer reset() {
          if (mark == UNSET_MARK) {
              throw new InvalidMarkException("Mark not set");
          }
          position = mark;
          return this;
      }

    (4)rewind()在读写模式下都可用,它单纯的将当前位置置0,同时取消mark标记,仅此而已;也就是说写模式下limit仍保持与Buffer容量相同,只是重头写而已;读模式下limit仍然与rewind()调用之前相同,也就是为flip()调用之前写模式下的position的最后位置,flip()调用后此位置变为了读模式的limit位置,即越界位置,代码如下:

    /**
     * Rewinds this buffer.
     * <p>
     * The position is set to zero, and the mark is cleared. The content of this
     * buffer is not changed.
     *
     * @return this buffer.
     */
    public final Buffer rewind() {
        position = 0;
        mark = UNSET_MARK;
        return this;
    }

    (5)flip()函数的作用是将写模式转变为读模式,即将写模式下的Buffer中内容的最后位置变为读模式下的limit位置,作为读越界位置,同时将当前读位置置为0,表示转换后重头开始读,同时再消除写模式下的mark标记,代码如下

    /**
     * Flips this buffer.
     * <p>
     * The limit is set to the current position, then the position is set to
     * zero, and the mark is cleared.
     * <p>
     * The content of this buffer is not changed.
     *
     * @return this buffer.
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = UNSET_MARK;
        return this;
    }

    (6)remaining()仅在读模式下使用,用来获取还未读出的字节数。

    • /**
       * Returns the number of remaining elements in this buffer, that is
       * {@code limit - position}.
       *
       * @return the number of remaining elements in this buffer.
       */
      public final int remaining() {
          return limit - position;
      }

    (7)Buffer的抽象子类ByteBuffer的compact()方法也蛮重要的。compact()的作用是压缩数据。比如当前EOF是6,当前指针指向2(即0,1的数据已经写出了,没用了),那么compact方法将把2,3,4,5的数据挪到0,1,2,3的位置,然后指针指向4的位置。这样的意思是,从4的位置接着再写入数据。

    /**
     * Compacts this byte buffer.
     * <p>
     * The remaining bytes will be moved to the head of the
     * buffer, starting from position zero. Then the position is set to
     * {@code remaining()}; the limit is set to capacity; the mark is
     * cleared.
     *
     * @return {@code this}
     * @throws ReadOnlyBufferException
     *                if no changes may be made to the contents of this buffer.
     */
    public abstract ByteBuffer compact();

    (8)equals()

    当满足下列条件时,表示两个Buffer相等:

    • 有相同的类型(byte、char、int等)。
    • Buffer中剩余的byte、char等的个数相等。
    • Buffer中所有剩余的byte、char等都相同。

    equals只是比较Buffer的一部分,不是每一个在它里面的元素都比较(即它只比较Buffer中的剩余元素)。

    以ByteBuffer为例

    • /**
       * 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></li>
       *
       * </ol>
       *
       * <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;
      }

    (9)compareTo()

    compareTo()方法比较两个Buffer的剩余元素(byte、char等), 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer:

    • 第一个不相等的元素小于另一个Buffer中对应的元素 。
    • 所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。

    以ByteBuffer为例

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

    补充:

    • 由于ByteBuffer是非线程安全的,所以多线程访问的时候也必须加锁。

    • ByteBuffer在内部也是利用byte[]作为内存缓冲区,只不过多提供了一些标记变量而已。当多线程访问的时候,可以清楚的知道当前数据的位置。

    转载出处——http://blog.csdn.net/chy555chy/article
  • 相关阅读:
    10.18
    10.16~10.17笔记
    JS
    10.8~10.11
    9.28~9.29
    9.27 代码笔记
    代码复习(9.26)
    9.19 链家
    9.18笔记
    9.17 定位
  • 原文地址:https://www.cnblogs.com/yixiu868/p/8011404.html
Copyright © 2011-2022 走看看