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 <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 <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> + <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 <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 <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);
-
咦, 咋么都是抽象方法呐, 自习看一下层级结构:
-
稍微看了一下, 它们的实现类在HeapByteBuffer和DirectByteBuffer中, 后者还调用了sun.misc.unsafe魔术类的方法, 在此就不做衍生了, 有兴趣的自己去撸源码。
-
-