Buffer源码

news2024/12/25 12:16:56

介绍

首先 Buffer 是一个能存储基本数据类型的容器(除了 Boolean 类型),从 java.nio 包的继承结构就能看出来。

image-20230702200217263

Java中的Buffer类是一个抽象类。Buffer类提供了一种将数据存储在内存中的方式,并提供了一些操作数据的方法。Buffer类可以存储不同类型的数据,并且可以方便地进行读取和写入操作。

常用的Buffer类有ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer和DoubleBuffer。这些Buffer类分别用于存储不同类型的数据,并且提供了相应的读写操作方法。

常量&变量

    /**
     * The characteristics of Spliterators that traverse and split elements
     * maintained in Buffers.
     * 在缓冲区中维护遍历和分割元素的拆分特征 TODO
     */
    static final int SPLITERATOR_CHARACTERISTICS =
        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;

    // Invariants: mark <= position <= limit <= capacity
    /**
     * 一个新创建的 Buffer 具有以下几个性质:
     *
     * 它的 position 是 0;
     * mark 没有被定义(实际上是 -1);
     * 而 limit 值可能是 0,也可能是其他值,这取决于这个 Buffer 的类型;
     * Buffer 中每一个元素值都被初始化为 0
     */
    //当调用 reset() 方法被调用时,一个 Buffer 的 mark 值会被设定为当前的 position 值的大小。
    //如果mark=-1 ,会reset失败
    private int mark = -1;
    //它是下一个要读或者写的元素的索引,它是非负的且不会超过 limit 的大小。
    private int position = 0;
    //它是可以读或者写的最后一个元素的索引,它是非负的且不会超过 capacity 的大小。
    private int limit;
    //它表示一个 Buffer 包含的元素数量,它是非负且恒定不变的
    private int capacity;

    // Used only by direct buffers
    // NOTE: hoisted here for speed in JNI GetDirectBufferAddress
    //这个属性只有在当前 Buffer 为 Direct Buffer 时才会使用
    long address;
  1. Capacity(容量):表示Buffer对象中可以存储的数据的最大数量。该值不能被更改。
  2. Position(位置):表示当前向Buffer对象中读取或写入数据的位置。
  3. Limit(限制):表示Buffer对象中可以读取或写入的数据的范围,即limit之后的数据不能读取或写入。
  4. Mark(标记):表示当前位置的一个备份,在调用reset()方法时,将回到该备份的位置。

构造方法

创建一个包含给定标记、位置、限制和容量的缓冲区。

    // Creates a new buffer with the given mark, position, limit, and capacity,
    // after checking invariants.
    //包内私有的构造器
    Buffer(int mark, int pos, int lim, int cap) {       // package-private
        //缓冲区容量小于0时抛出异常
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        //根据传参设置缓冲区大小
        this.capacity = cap;
        //设置limit
        limit(lim);
        //设置position
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                //mark大于pos并且mark大于等于0时会抛出异常
                throw new IllegalArgumentException("mark > position: ("
                                                   + mark + " > " + pos + ")");
            //设置mark
            this.mark = mark;
        }
    }

常用方法

capacity

capacity()方法用于返回缓冲区的容量,即缓冲区中可以存储的元素的最大数量。

    /**
     * Returns this buffer's capacity.
     *
     * @return  The capacity of this buffer
     * 返回缓冲区容量
     */
    public final int capacity() {
        return capacity;
    }

position

用于获取缓冲区的当前位置。在缓冲区中,位置是指下一个要被读取或写入的元素的索引,初始位置为0。通过调用position()方法,可以获取当前位置,也可以将当前位置设置为指定值。

    /**
     * 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) {
        //要设置的position值不能大于limit值或者小于0,否则就抛出异常。
        if ((newPosition > limit) || (newPosition < 0))
            throw createPositionException(newPosition);
        //如果设置的新的游标值比mark值小,就重置mark值为-1.
        if (mark > newPosition) mark = -1;
        //设置游标
        position = newPosition;
        return this;
    }

limit

用于设置缓冲区的限制(limit),调用limit方法后,缓冲区的限制将被设置为指定的值。如果缓冲区的当前位置大于新的限制值,则当前位置将被设置为新的限制值。

    /**
     * Returns this buffer's limit.
     *
     * @return  The limit of this buffer
     * 返回缓冲区的可用数据长度。
     */
    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
     *           设置缓冲区的limit值,同时会保证position和mark值保证这几个值的关系符合规则。
     */
    public final Buffer limit(int newLimit) {
        //对要设置的新limit进行检查,如果大于缓冲区容量或者小于0就抛出异常
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        //设置limit
        limit = newLimit;
        //如果游标比可操作的最大数组下标还大的话,就把游标设置为limit
        if (position > newLimit) position = newLimit;
        //如果mark > limit,重置mark。
        if (mark > newLimit) mark = -1;
        return this;
    }

mark

mark方法会将一个标记设置在当前位置,以便在后续的操作中可以返回到这个位置。这个标记可以通过调用reset方法返回。

    /**
     * Sets this buffer's mark at its position.
     *
     * @return  This buffer
     * 标记当前position位置。
     */
    public final Buffer mark() {
        mark = position;
        return this;
    }

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;
        //标记小于0时抛出异常
        if (m < 0)
            throw new InvalidMarkException();
        //重置游标至标记处
        position = m;
        return this;
    }

clear

用于重置缓冲区的位置、极限和标记。它将position设置为0,将标记设置为-1,并将极限设置为容量。此方法不会清除缓冲区中的数据。调用该方法后,您可以重新填充缓冲区或读取缓冲区中的现有数据。

    /**
     * Clears this buffer.  The position is set to zero, the limit is set to
     * the capacity, and the mark is discarded.
     *
     * <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
     * 清空缓冲区,其实就设置游标为0,limit设置回capacity值,mark重置,数据还是存在的。
     */
    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

flip

flip方法是用于将写模式下的缓冲区切换为读模式。在写模式下,缓冲区的指针指向缓冲区的末尾,而在读模式下,指针指向缓冲区的开头。当需要读取已写入的数据时,需要使用flip方法切换模式。

    /**
     * Flips this buffer.  The limit is set to the current position and then
     * the position is set to zero.  If the mark is defined then it is
     * discarded.
     *
     * <p> After a sequence of channel-read or <i>put</i> operations, invoke
     * this method to prepare for a sequence of channel-write or relative
     * <i>get</i> operations.  For example:
     *
     * <blockquote><pre>
     * buf.put(magic);    // Prepend header
     * in.read(buf);      // Read data into rest of buffer
     * buf.flip();        // Flip buffer
     * out.write(buf);    // Write header + data to channel</pre></blockquote>
     *
     * <p> This method is often used in conjunction with the {@link
     * java.nio.ByteBuffer#compact compact} method when transferring data from
     * one place to another.  </p>
     *
     * @return  This buffer
     *  缓冲区创建时默认是写模式的,这个方法把缓冲区改为读模式。
     *  每次通过通道往存储设备中写数据都需要调用此方法把缓冲区设置为读模式。读取缓冲区的数据。
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

rewind

将缓冲区的position重置为0,表示可以重新读取缓冲区的内容。此方法不会改变缓冲区的limit和capacity。

    /**
     * Rewinds this buffer.  The position is set to zero and the mark is
     * discarded.
     *
     * <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;
    }

remaining

用于计算缓冲区中还剩余的未读元素数量。具体来说,remaining()方法返回值是一个int类型的整数,表示当前缓冲区中还有多少个元素可以被读取。

    /**
     * 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() {
        int rem = limit - position;
        return rem > 0 ? rem : 0;
    }

    /**
     * Tells whether there are any elements between the current position and
     * the limit.
     *
     * @return  <tt>true</tt> if, and only if, there is at least one element
     *          remaining in this buffer
     *          返回是否还有数据可读或者可写。
     */
    public final boolean hasRemaining() {
        return position < limit;
    }

nextGetIndex

用于获取下一个get(读取)操作的位置。读取操作和写入操作都是在当前位置(position)进行的。nextGetIndex方法返回的是当前位置加上1,即下一个读取操作应该从哪个位置开始读取数据。如果当前位置已经是buffer的limit值,那么下一个读取操作将无法进行,因为读取操作不能超过limit。

    /**
     * Checks the current position against the limit, throwing a {@link
     * BufferUnderflowException} if it is not smaller than the limit, and then
     * increments the position.
     *
     * @return  The current position value, before it is incremented
     * 读模式下游标往右移一位,也就是跳过一个数据。
     * 返回移动前的游标值。
     */
    final int nextGetIndex() {                          // package-private
        int p = position;
        //因为游标加一 所以要确保游标加一前要小于等于limit
        if (p >= limit)
            //当前游标>=limit抛出异常
            throw new BufferUnderflowException();
        position = p + 1;
        return p;
    }

    /**
     * 读模式下游标往右移动n位。
     * 返回移动前的游标
     * @param nb
     * @return
     */
    final int nextGetIndex(int nb) {                    // package-private
        int p = position;
        if (limit - p < nb)
            //判断加n后的游标是否大于limit,大于就抛出异常
            throw new BufferUnderflowException();
        position = p + nb;
        //返回移动前的游标。
        return p;
    }

nextPutIndex

用于返回下一个可写入的位置的索引。该方法会检查缓冲区的容量以确保缓冲区已分配足够的空间来写入数据。如果缓冲区容量不足,则会调用expand()方法来扩展缓冲区大小

    /**
     * Checks the current position against the limit, throwing a {@link
     * BufferOverflowException} if it is not smaller than the limit, and then
     * increments the position.
     *
     * @return  The current position value, before it is incremented
     * 写模式下游标往右移动1位。
     *  返回移动前的游标
     */
    final int nextPutIndex() {                          // package-private
        int p = position;
        if (p >= limit)
            throw new BufferOverflowException();
        position = p + 1;
        return p;
    }

    /**
     * 写模式下游标往右移动n位。
     *  返回移动前的游标
     * @param nb
     * @return
     */
    final int nextPutIndex(int nb) {                    // package-private
        int p = position;
        if (limit - p < nb)
            throw new BufferOverflowException();
        position = p + nb;
        return p;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/727317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

原型模式:如何最快速地clone一个HashMap散列表?

我们还像学习建造者模式一样 思考 什么是原型模式&#xff1f;主要解决哪些问题&#xff1f; 如果对象的创建成本比较大&#xff0c;而同一个类的不同对象之间差别不大&#xff08;大部分字段都相同&#xff09;&#xff0c;在这种情况下&#xff0c;我们可以利用对已有对象…

5 类型转换

类型转换是变量与变量之间的&#xff0c;变量与常量之间是赋值。 5.1 自动类型转换 小转大。如下图所示&#xff0c;注意&#xff0c;byte不能自动转为char类型&#xff0c;因为类型不匹配&#xff0c;但是可以通过强转来转。 代码如下&#xff1a; byte a 10;int b a; 5.2…

测试流程实战(1)

目录&#xff1a; 测试流程梳理业务架构分析实战测试用例管理实战Bug 录入与管理实战如何写 Bug 报告编写 Bug 报告 1.测试流程梳理 2.业务架构分析实战 使用 plantuml 完成登录流程时序图plantuml 官网&#xff1a;使用简单的文字描述画UML图的开源工具。plantuml 在线绘图…

【HDC.Cloud 2023】华为开发者大会2023来了!这份PaaS参会指南请查收!

了不起的开发者们&#xff0c;我们来啦&#xff01; 7月7日&#xff0c;华为开发者大会2023 ( Cloud )将拉开帷幕 PaaS诚邀您参加这场不容错过的年度开发者盛会&#xff0c;让我们一起开启探索之旅。 我们将为开发者们提供PaaS生态资源工具、学习成长、分享交流、生态实践等…

Docker 安装Flowable-ui

查询镜像 docker search flowable-ui 拉取镜像 docker pull flowable/flowable-ui 使用默认数据库&#xff08;默认H2数据库&#xff09; docker run --name flowable-ui \ -p 8080:8080 \ -d --restartalways \ flowable/flowable-ui 使用MySQL数据库 docker run --name…

Windows环境Jmeter调优

在windows环境下搭建jmeter的压测实验环境&#xff0c;需要对操作系统默认的一些个参数进行设置&#xff0c;以提高并发能力。特别是作为压力机的时候。 Socket 编程时&#xff0c;单机最多可以建立多少个 TCP 连接&#xff0c;受到操作系统的影响。 Windows 下单机的TCP连接数…

simulink while/if/switch case

目录 while if Switch case while 循环设置100次 if Switch case 子模块可以用法和if一样

vue3混入mixins

Vue中混入的作用是分发组建中可复用的功能 新建mixins文件夹&#xff0c;新建mixins.ts文件 import { ref } from vue;export default function () {const num ref(0);const fav ref(false);const fvbtn () > {num.value 1;fav.value true;setTimeout(() > {fav.va…

六西格玛在服务业的案例:如何通过过程改进提高客户满意度?

六西格玛是一种质量管理方法&#xff0c;旨在通过减少缺陷和提高效率用以改善业务流程。在服务行业&#xff0c;六西格玛可以帮助企业提高客户满意度&#xff0c;缩短服务周期&#xff0c;降低成本。下面张驰咨询给大家分享一个服务行业的六西格玛案例。 1、背景介绍 这家服务…

Docker学习笔记26

Docker stack应用&#xff1a; 1&#xff09;Docker 层级关系中的最高层次——stack&#xff0c;一个stack就是一组有关联的服务的组合&#xff0c;可以一起编排&#xff0c;一起管理。 早期&#xff0c;使用service来发布服务。但是service每次只能发布一个service。 yaml可…

(Windows版)PostgreSQL - TimescaleDB插件的2种安装方法

一&#xff1a;下载pgsql相对应的timescaledb插件包 下载地址&#xff1a;https://github.com/timescale/timescaledb/releases/tag/2.10.1 二&#xff1a;开始安装 注意&#xff1a;在安装前&#xff0c;先关闭PostgreSQL 服务 方法一 1.【控制面板\系统和安全\管理工具\…

手把手教-单片机和w5500模块基于rt-thread中wiznet软件包的使用

一、开发环境 硬件&#xff1a;stm32f407野火开发板&#xff0c;w5500模块 软件&#xff1a;rt-thread操作系统&#xff0c;wiznet软件包&#xff0c;基于正点原子stm32f407的bsp包&#xff08;需要根据实际修改系统时钟&#xff09; 引脚连接方式&#xff1a; 单片机引脚&…

镀金积分球——激光红外功率测量

中波红外激光作为干扰光源&#xff0c;可对红外导引头及红外观瞄设备实施压制式干扰&#xff0c;激光器远场功率密度分布是评价其作战效能的重要指标。通用的激光功率测量设备多基于近场&#xff0c;并且因接收口径有限&#xff0c;只能检测到很小特定区域内的激光功率&#xf…

专心当个工程师,也挺好~

正文 大家好&#xff0c;我是bug菌~ 今天主要是分享一些职场上的小小领悟吧&#xff1a; 1 双向思维 一个人有他的缺点&#xff0c;也必定存在其优点&#xff0c;不要动不动就局限的认为这个人这也不行&#xff0c;那也不行&#xff0c;再说当初你咋就把他招进来了呢&#xff1…

【Redis 】Redis 的脑裂现象和解决方案

文章目录 Redis 中的脑裂是什么&#xff1f;脑裂有什么影响&#xff1f;数据丢失一定是发生了脑裂吗&#xff1f;如何解决脑裂问题&#xff1f; Redis 中的脑裂是什么&#xff1f; 从名字分析&#xff0c;脑裂现象就是大脑裂开了&#xff0c;一个人如果有两个大脑&#xff0c;…

Golang每日一练(leetDay0116) 路径交叉、回文对

目录 335. 路径交叉 Self-crossing &#x1f31f;&#x1f31f;&#x1f31f; 336. 回文对 Palindrome Pairs &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/…

【PCIE】链路训练的TS训练序列解释

TS码流解释 TS1和TS2有序集合是PCIe&#xff08;Peripheral Component Interconnect Express&#xff09;协议中使用的一种特殊数据包格式。这些有序集合用于在PCIe链路的训练阶段进行通信和控制。 TS1&#xff08;Training Sequence 1&#xff09;有序集合&#xff1a;TS1有…

Django实现简单的音乐播放器 2

在《Django实现简单的音乐播放器 1》前期准备的基础上开始开发。 效果&#xff1a; 目录 项目视图 创建视图方法 路由加载视图 加载模板 创建首页html文件 加载静态资源文件 加载静态文件 使用方法 启动服务器 加载数据表 创建表模型 生成表迁移 执行创建表 插入…

CRM中的多业务场景管理是什么?有哪些功能?

为了适应不同的客户需求和市场变化&#xff0c;很多企业开展了多个业务场景&#xff08;产品线、销售渠道等&#xff09;。这些多业务场景给企业的客户管理带来了很大的挑战&#xff0c;如何有效地管理多种业务是企业急需解决的问题。下面说说&#xff0c;多业务场景下的CRM管理…

在Window仿Linux终端命令学习Python

在Window仿Linux终端命令学习Python Echox 命令 -- 主要带颜色输出ls 命令findx 命令~~待续~~ python3 Echox 命令 – 主要带颜色输出 查看 python输出颜色&#xff08;终端控制台&#xff09; ls 命令 1、getopt 模块参数解析 &#xff1a; Python 命令行参数 2、os.getcwd…