• NIO-BufferAPI


    一 核心要素

    1. capacity (容量);不能为负,不可更改;就是buffer的长度(buffer.length)
    2. limit (限制);指第一个不可被读入缓冲区元素的位置;不可为负,若position大于limit,那么limit就是position;
    3. position (位置);指下一个被读入缓冲区元素的位置;不可为负,小于limit,默认索引由0开始;
    4. mark (标记);指在缓冲区设置标记;若调用reset()方法会回到position的位置;如果未设置mark调用reset()方法会报异常;如果positon或者limt小于mark时,mark被丢弃,其指为 -1;

    各要素之间的关系:

    0 <= mark <= position <= limit <= capacity

    二 Buffer 架构体系

    Buffer 是在多线程环境下是非安全操作,如果要在多线程情况下使用通常要加锁;Buffer 和其子类都是抽象类,其不能被实例化,需通过wrap(byte[] byte)方法来构建不同的缓冲区,具体的架构体系如下:

    Object (java.lang)
    -->Buffer (java.nio)
    ---->IntBuffer (java.nio)
    ---->FloatBuffer (java.nio)
    ---->CharBuffer (java.nio)
    ---->DoubleBuffer (java.nio)
    ---->ShortBuffer (java.nio)
    ---->LongBuffer (java.nio)
    ---->ByteBuffer (java.nio)
    
    

    三 Buffer 方法介绍

    Buffer 的子类完全实现了其父类的方法,所以本文示例都是使用其子类举例分析;

    3.1 position()

    int position() 方法是返回缓冲区的位置;

     @Test
        public void testPosition(){
            byte[] bytes = {15,17,25,13,46,18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 获得位置
            int position = wrap.position();
            System.out.println(position);//0
            // 设置位置
            Buffer position1 = wrap.position(5);
            //[pos=5 lim=6 cap=6]
            System.out.println(position1);
    
        }
    

    3.2 limit()

    int limit() 返回缓冲区的限制;如果 position > limit ,position就是limit,自行验证;

    @Test
        public void testLimit(){
            byte[] bytes = {15,17,25,13,46,18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 获得限制
            int limit = wrap.limit();
            System.out.println(limit);//6
            // 设置限制
            Buffer limit1 = wrap.limit(3);
            //[pos=0 lim=3 cap=6]
            System.out.println(limit1);
            // 输出缓冲区元素
            for (int i=0; i<bytes.length; i++){
                // 只输出 15 17 25 继续get会报 BufferUnderflowException
                System.out.println(wrap.get());
            }
        }
    

    3.3 mark()

    Buffer mark() 设置缓冲区标记;如果未设置mark调用reset()会报 InvalidMarkException 异常,自行验证;

    @Test
        public void testMark() {
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 设置位置
            wrap.position(1);
            // 设置标记
            wrap.mark();
            // [pos=1 lim=6 cap=6]
            System.out.println(wrap);
            // 改变位置
            wrap.position(4);
            // 调用reset
            wrap.reset();
            //  [pos=1 lim=6 cap=6]
            System.out.println(wrap);
    
        }
    

    3.4 capacity()

    int capacity() 返回缓冲区的容量,不可改变;

    @Test
        public void test(){
    
            byte[] bytes = new byte[25];
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 获得缓冲区容量
            int capacity = wrap.capacity();
            // 25
            System.out.println(capacity);
        }
    

    3.5 remaining()

    int remaining() 返回当前位置和限制之间的大小;即 remaining = limit - position;

    @Test
        public void testRemaining() {
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 获得缓冲区的元素个数
            int remaining = wrap.remaining();
            // 6
            System.out.println(remaining);
            // 设置位置
            wrap.position(1);
            // 设置limit
            wrap.limit(5);
            // 重新获得缓冲区的元素个数
            int remaining1 = wrap.remaining();
            //4
            System.out.println(remaining1);
    
        }
    

    3.6 isDirect()

    abstract boolean isDirect() 判断该缓冲区是否是直接缓冲区;平常的缓冲区都是非直接缓冲区,即在jvm内部创建的缓冲区,我们调用Buffer相关的方法都会走jvm内部缓冲区,其性能不如直接缓存区快;直接缓冲区是指无需创建jvm内部缓冲区,直接跟计算级的内存空间交互,其速度较快;

        @Test
        public void testIsDirect() {
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 判断是否是直接缓冲区
            boolean direct = wrap.isDirect();
            // false
            System.out.println(direct);
            // 分配直接缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8);
            boolean direct1 = byteBuffer.isDirect();
            // true
            System.out.println(direct1);
    
        }
    

    3.7 isReadOnly()

    abstract boolean isReadOnly() 判断是否是只读缓冲区;

     @Test
        public void testIsDeadOnly() {
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 判断是否是只读缓冲区
            boolean readOnly = wrap.isReadOnly();
            // false
            System.out.println(readOnly);
    
        }
    

    3.8 clean()

    Buffer clear() 是还原缓冲区的初始状态,记住不是字面的意思清除缓冲区数据;

        @Test
        public void testClean() {
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            wrap.position(2);
            wrap.limit(5);
            // [pos=2 lim=5 cap=6]
            System.out.println(wrap);
            // 还原缓冲区状态
            wrap.clear();
            // [pos=0 lim=6 cap=6]
            System.out.println(wrap);
    
        }
    

    其主要使用于重新写入数据至缓冲区;通常在通道read,put 操作之前调用为了填充缓冲区;

    示例:

        @Test
        public void testClean2() {
            CharBuffer wrap = CharBuffer.allocate(24);
            wrap.put("youku1327");
            wrap.clear();
            wrap.put("知识追寻者");
            wrap.rewind();
            for (int i=0; i<wrap.limit();i++){
                //知识追寻者1327    
                System.out.print(wrap.get());
            }
    
        }
    

    源码:

        public final Buffer clear() {
        	// 位置清0
            position = 0;
            // 调整限制等于容量
            limit = capacity;
            // 标记调整为默认值
            mark = -1;
            return this;
        }
    

    3.9 flip()

    Buffer flip() 翻转缓冲区;不是字面意思上的将缓冲区的数据倒转,是指截取的意思;将限制设置为位置所在的当前值,将位置清0,如果有定义标记,则抛弃标记;

    源码:

        public final Buffer flip() {
        // 将限制设置当前位置的值
            limit = position;
            // 位置清 0
            position = 0;
            // 抛弃标记
            mark = -1;
            return this;
        }
    

    示例:

    	@Test
        public void testFilp() {
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            wrap.position(2);
            wrap.mark();
            // 翻转前 [pos=2 lim=6 cap=6]
            System.out.println(wrap);
            // 翻转
            wrap.flip();
            // 反正后 [pos=0 lim=2 cap=6]
            System.out.println(wrap);
            // 输出缓冲区元素
            for (int i=0; i<wrap.limit(); i++){
                // 15 17
                System.out.println(wrap.get());
            }
    
        }
    

    其通常在一系列 通道 put 或者 read 操作之后调用此方法为通道的write或者 get操作做准备;

    示例:

       @Test
        public void testFilp2() {
            CharBuffer wrap = CharBuffer.allocate(15);
            wrap.put("公众号:知识追寻者");
            // 翻转
            wrap.flip();
            for (int i=0; i<wrap.limit(); i++){
                // 公众号:知识追寻着
                System.out.print(wrap.get());
            }
        }
    

    3.10 hasArray()

    abstract boolean hasArray() 判断底层是否支持数组的实现;

        @Test
        public void testHasArray(){
            // 间接缓存
            ByteBuffer allocate = ByteBuffer.allocate(10);
            boolean hasArray = allocate.hasArray();
            // true
            System.out.println(hasArray);
            // 直接缓存
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);
            boolean hasArray1 = byteBuffer.hasArray();
            // false
            System.out.println(hasArray1);
    
        }
    

    3.11 hasRemaining()

    boolean hasRemaining() 判断 limit 和 position直接是否有元素;经常使用于缓冲区读取数据;

       @Test
        public void testHasRemaining(){
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            while (wrap.hasRemaining()){
                // 15 17 25 13 46 18
                System.out.println(wrap.get());
            }
        }
    

    3.12 rewind()

    Buffer rewind() 重绕缓冲区;其通常在通道write 或者 get 操作之前调用,为了重新读取数据;注意其限制不变;

    源码:

    public final Buffer rewind() {
    	// 位置设置为0
            position = 0;
            // 抛弃标记
            mark = -1;
            return this;
        }
    

    示例:

     @Test
        public void testRewind(){
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            while (wrap.hasRemaining()){
                // 15 17 25 13 46 18
                System.out.println(wrap.get());
            }
            // 重绕缓冲区
            wrap.rewind();
            while (wrap.hasRemaining()){
                // 15 17 25 13 46 18
                System.out.println(wrap.get());
            }
        }
    

    3.13 arrayOffset()

    abstract int arrayOffset() 返回写入缓冲区第一个元素的偏移,可选操作;

    	 @Test
        public void testOffset(){
            byte[] bytes = {15, 17, 25, 13, 46, 18};
            ByteBuffer wrap = ByteBuffer.wrap(bytes);
            // 获得偏移
            int arrayOffset = wrap.arrayOffset();
            // 0
            System.out.println(arrayOffset);
        }
    

    源码:

     public final int arrayOffset() {
            if (hb == null)
                throw new UnsupportedOperationException();
            if (isReadOnly)
                throw new ReadOnlyBufferException();
            return offset;
        }
    
    final int offset;
    
  • 相关阅读:
    Unity Notes调制粒子系统的颗粒的最大数目
    Swift编程语言学习2.1——基础运营商(在)
    JavaScript语言基础知识6
    算法题:合并两个有序列表
    DDFT
    Java For循环效率试验
    Delphi ORD
    Delphi TcxTreeList 节点添加图片
    SQL Server 除法 不起作用的问题
    Delphi 继承基类的窗体,并显示基类的控件操作。
  • 原文地址:https://www.cnblogs.com/zszxz/p/12231937.html
Copyright © 2020-2023  润新知