缓冲区Buffer

缓冲区介绍

abstract class Buffer
7个直接子类
abstract class ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer。
NIO中的Buffer是一个用于存储脚本数据类型的容器,以类似于数组有序的方式来存储和组织数据。

Buffer类的使用

API:
在这里插入图片描述

包装数据与获得容量

	//Invariants: mark <= position <= limit <= capacity
	private int mark = -1; //标记
    private int position = 0; //位置
    private int limit; //限制
    private int capacity; //容量

Buffer的7个子类也是抽象的,不能通过new 实例化,使用静态方法wrap()实现。wrap方法将数组放入缓冲区,来构建存储不同数据类型的缓冲区。

	byte[] byteArray = new byte[]{1,2,3};
    ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
    System.out.println(byteBuffer.getClass().getName());
    System.out.println(byteBuffer.capacity());

output:
	java.nio.HeapByteBuffer
	3

wrap源码

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

ByteBuffer类缓冲区的原理是使用byte[]数组进行数据的保存,在后续使用指定的API来操作这个数组已达到操作缓冲区的目的。

	HeapByteBuffer(byte[] buf, int off, int len) { // package-private
        super(-1, off, off + len, buf.length, buf, 0);
    }

	ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset){
        super(mark, pos, lim, cap);
        this.hb = hb;
        this.offset = offset;
    }

从源码可以看到,缓冲区存储的数据还是存储在byte[]字节数组中。使用缓冲区与使用byte[]字节数组的优点在于缓冲区将存储数据的byte[]字节数组内容与相关的信息整合在一个Buffer类中,将数据与缓冲区中的信息进行了整合并封装,便于获得相关的信息及处理数据。

限制获取与设置

限制代表第一个不应该读取或写入元素的index

limit源码:

	/**
     * Returns this buffer's limit.
     */
    public final int limit() {
        return limit;
    }
	/**
     * Sets this buffer's limit.  If the position is larger than the new limit
     * then it is set to the new 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;
    }

示例

		char[] charArr = new char[]{'a','b','c','d','e','f'};
        CharBuffer charBuffer = CharBuffer.wrap(charArr);
        System.out.println("capacity = " + charBuffer.capacity() + " limit=" + charBuffer.limit());
        
        charBuffer.limit(3);
        System.out.println("capacity = " + charBuffer.capacity() + " limit=" + charBuffer.limit());
        
        charBuffer.put(0,'h');
        charBuffer.put(1,'i');
        charBuffer.put(2,'j');
        charBuffer.put(3,'k');  //第一个不可读不可写的索引
        charBuffer.put(4,'l');
output:
	capacity = 6 limit=6
	capacity = 6 limit=3
	java.lang.IndexOutOfBoundsException
		……

Limit的使用场景是当反复向缓冲区中存储数据时使用,如第一次向缓冲区写入 A到G 7个字符,然后全部读取,第二次向缓冲区写入1到4 4个字符,如果读取到1、2、3、4、E、F、G是错误的,需要结合limit限制读取范围。

位置获取与设置

源码

/**
     * Returns this buffer's position.
     *
     * @return  The position of this buffer
     */
    public final int position() {
        return position;
    }

    /**
     * Sets this buffer's position.  If the mark is defined and larger than the
     * new position then it is discarded.
     *
     * @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;
    }

剩余空间大小获取

返回当前位置与limit之间的元素数

/**
     * 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;
    }
    ```

## 使用Buffer mark()方法处理标记
缓冲区的 标记是一个索引,在调用reset()方法时,会将缓冲区的position位置重置为该索引。标记mark并不是必须的。定义mark时,不能将其定义为负数,并且不能让他大于position。如果定义了mark,则在将position或limit调整为小于该mark的值时,该mark将被丢弃,丢弃后的mark值是-1.如果未定义mark,那么调用reset方法将导致抛出invalidMarkException。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章