文章目录
ByteBuffer类提供了6类操作。
- 以绝对位置和相对位置读写单个字节的get()和put()方法
- 使用相对批量get(byte[] dst)方法可以将缓冲区中的连续字节传输到byte[] dst目标数组中。
- 使用相对批量put(byte[] src)方法可以将byte[]数组或其他字节缓冲区中的连续字节存储到此缓冲区中。
- 使用相对和绝对getType和putType方法可以按照字节顺序在字节序列中读写其他基本数据类型的值,方法getType和putType可以进行数据类型的自动转换。
- 提供了创建视图缓冲区的方法,这些方法允许将字节缓冲区视为包含其他基本类型值的缓冲区,这些方法有asCharBuffer()、asDoubleBuffer()、asFloatBuffer()、asIntBuffer()、asLongBuffer()、asShortBuffer()。
- 提供了对字节缓冲区进行压缩(compacting)、复制(duplicating)和截取(slicing)的方法。
创建堆缓冲区和直接缓冲区
字节缓冲区分为直接字节缓冲区(JVM会尽量直接对内核空间进行IO操作,避免将缓冲区内容复制到中间缓冲区,提高效率)和非直接字节缓冲区。
allocateDirect()创建直接字节缓冲区,通过工厂方法allocateDirect()返回的缓冲区进行内存的分配和释放所需要的时间成本通常要高于非直接缓冲区。
allocate源码:
/**
* 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. 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);
}
/**
* 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. It will have a {@link #array backing array},
* and its {@link #arrayOffset array offset} will be zero.
*
* @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);
}
直接缓冲区与非直接缓冲区运行效率比较
long begin = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocateDirect(1000000000);
for (int i = 0; i < 1000000000; i++) {
buffer.put((byte)100);
}
System.out.println(System.currentTimeMillis() - begin);
output:
1896
long begin = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocate(1000000000);
for (int i = 0; i < 1000000000; i++) {
buffer.put((byte)100);
}
System.out.println(System.currentTimeMillis() - begin);
output:
2575
直接缓冲区运行效率要高些。直接缓冲区(DIrectByteBuffer)内部使用sun.misc.Unsafe类进行值的处理。Unsafe的作用是JVM与操作系统进行直接通信,提高程序运行的效率。
public ByteBuffer put(byte x) {
unsafe.putByte(ix(nextPutIndex()), ((x)));
return this;
}
非直接缓冲区(HeapByteBuffer)在内部直接对byte[] hb字节数组进行操作,而且还是在JVM的堆中进行数据处理,运行效率相对慢些。
public ByteBuffer put(byte x) {
hb[ix(nextPutIndex())] = x;
return this;
}
包装wrap数据的处理
wrap(byte[] array):
/**
* 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>
*
* @param array
* The array that will back this buffer
*
* @return The new byte buffer
*/
public static ByteBuffer wrap(byte[] array) {
return wrap(array, 0, array.length);
}
wrap(byte[] array, int offset, int length):
/**
* 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 will be
* <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
* will be <tt>offset + length</tt>, 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>
*
* @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
*
* @throws IndexOutOfBoundsException
* If the preconditions on the <tt>offset</tt> and <tt>length</tt>
* parameters do not hold
*/
public static ByteBuffer wrap(byte[] array, int offset, int length)
{
try {
return new HeapByteBuffer(array, offset, length);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}
}
注意:wrap(byte[] array, int offset, int length)参数offset只是设置缓冲区的position值,length确定limit值
Demo:
byte[] byteArr = new byte[]{1,2,3,4,5,6,7,8};
ByteBuffer byteBuffer1 = ByteBuffer.wrap(byteArr);
ByteBuffer byteBuffer2 = ByteBuffer.wrap(byteArr,2,4);
System.out.println("bytebuffer1 capacity=" + byteBuffer1.capacity() + " limit=" + byteBuffer1.limit() + " position=" + byteBuffer1.position());
System.out.println("bytebuffer2 capacity=