使用ByteBuffer

本文详细介绍了Java中的ByteBuffer类,包括如何创建堆缓冲区和直接缓冲区,探讨了直接缓冲区与非直接缓冲区的运行效率差异。内容涵盖了ByteBuffer的基本操作如put和get方法,以及视图缓冲区、字节顺序、只读缓冲区的创建等。通过实例展示了ByteBuffer在处理数据转换和传输中的应用。
摘要由CSDN通过智能技术生成

ByteBuffer类提供了6类操作。

  1. 以绝对位置和相对位置读写单个字节的get()和put()方法
  2. 使用相对批量get(byte[] dst)方法可以将缓冲区中的连续字节传输到byte[] dst目标数组中。
  3. 使用相对批量put(byte[] src)方法可以将byte[]数组或其他字节缓冲区中的连续字节存储到此缓冲区中。
  4. 使用相对和绝对getType和putType方法可以按照字节顺序在字节序列中读写其他基本数据类型的值,方法getType和putType可以进行数据类型的自动转换。
  5. 提供了创建视图缓冲区的方法,这些方法允许将字节缓冲区视为包含其他基本类型值的缓冲区,这些方法有asCharBuffer()、asDoubleBuffer()、asFloatBuffer()、asIntBuffer()、asLongBuffer()、asShortBuffer()。
  6. 提供了对字节缓冲区进行压缩(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=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值