• 中文
    • English
  • 注册
  • 查看作者
  • Java NIO关键概念之Buffer

    一、前言

    Java NIO的三大关键概念之一是Buffer,在一些文章/源代码中,我们也经常会看到Buffer相关的信息。Buffer到底是什么,Buffer的基本使用方法是什么,这是本文主要要说的。

    二、Buffer的基本概念

    自JDK1.4引入,是一个抽象类,在 包下,定义了一些通用的方法,并不能直接创建对象,在使用时,需要通过其具体的基础数据类型子类来创建对象。Java的基础数据类型中,除了 外,都有一个对应数据类型的子类,如ByteBuffer、IntBuffer等。

    Java NIO关键概念之Buffer

    通俗点说, Buffer是Java基础数据类型的数据容器 ,本质上其实就是一个相应基础数据类型的 数组 封装,并扩展了相关的属性、操作方法等以方便使用。(实现缓存数据、方便高效地操作数据,后面会有示例/源码说明)

    Buffer中,有几个重要的属性/概念,简单说明如下:

    Java NIO关键概念之Buffer

    简单来说,capacity是Buffer对应的数组的 容量值 ,limit是读/写的 限制值 ,position是数组中相关元素 位置 的索引值,这三个值都不会为负数,且这几个值的大小关系如下:

    Buffer作为一个数据容器,操作一个Buffer的一般过程如下:

    Java NIO关键概念之Buffer

    类作为一个 抽象 基类,提供了一些基本方法,如 、 等,可以返回其私有属性值,也提供了 (读/写模式切换)、 (清空数据)等设置属性值的操作方法,且这些方法都是用 关键字修饰的, 不可被重写

    而要创建一个Buffer对象,则只能通过对应基础数据类型的子类中的 方法来实现,同样,写数据、读数据,也需要调用相应子类中的相关 、 方法来实现。

    三、Buffer的基本使用&源码分析

    基本使用

    首先,通过一个例子演示下Buffer的基本使用:

    执行代码输出:

    从输出结果可以看出,随着对Buffer进行各种读/写操作,Buffer中的三个关键属性中,position、limit的值在不断变化,capacity的值固定不变,如下图所示:

    Java NIO关键概念之Buffer

    源码分析

    接下来,我们通过源码,看一下Buffer到底是如何实现示例中的相关功能的。

    示例代码中,几个关键类的关系如下图所示:

    Java NIO关键概念之Buffer

    1、 部分源码:

    2、 部分源码:(其它IntBuffer、CharBuffer等Buffer子类源码相似)

    类中的 、 、 这几个方法都只有抽象定义,具体实现在子类中,接下来看下 中的具体实现代码。

    3、 部分源码:

    以上,笔者只贴了部分关键代码,代码中已添加简单说明。更多详细代码可以去看源码,源码中有非常详细的相关注释。

    源码补充说明:

    1、对Buffer的清除、压缩、翻转等操作,在某种意义上来说,其实就是 对数据索引值position、limit的操作

    2、Buffer中的清除数据( 方法),并不会真正删除Buffer中数组中的元素,而是通过设置position、limit属性值的方式,修改Buffer的读/写位置与边界值。

    3、如果Buffer中的数据没有全部读完,就调用 方法的话,则可能会造成未读数据被覆盖掉,此时,如果想只清除已读数据,保留未读数据的话,可调用 方法。

    4、Buffer通过优秀的设计实现了可以方便灵活、简单高效地缓存/操作数据。

    Buffer的常用方法简单说明如下

    Java NIO关键概念之Buffer

    当然,buffer的子类中还有许多其它方法,用于更灵活地操作buffer,如 方法可指定索引值写数据, 方法可指定索引值读取数据等等,此处笔者就不一一列举了。

    Buffer的大小比较

    另外,需要说明的是,Buffer的具体基础数据类型子类都实现了 接口,并重写了 、 方法, 也就是说,Buffer是可以比较大小的,只是需满足特定条件:

    关键源码如下:

    从源码可知:

    1、判断两个buffer相等需满足以下条件:

    a、有相同的元素类型;(同为byte、int等)

    b、buffer中剩余元素的个数相等;

    c、buffer中剩余元素的值都一一对应相等。

    2、判断两个buffer大小根据以下条件判断:

    a、有相同的元素类型;(同为byte、int等)

    b、剩余第一个不相等元素的大小;(两个buffer中,从当前position开始依次比较;当出现第一个不相等的元素时,以该元素的大小比较结果,作为buffer大小的比较结果)

    c、剩余元素前面比较都相等,更长的那个大。(若依次比较buffer中的剩余元素后,其中一个buffer的剩余元素已经全部比较完,另一个buffer还存在元素没有参与比较,则还存在元素的buffer大。)

    从以上条件可以看出,判断buffer是否相等、buffer的大小,只会校验buffer中的“剩余”元素,并不会校验全部元素,这点需要注意。( 剩余元素指从position到limit之间的元素 ,也就是 的差值)

    四、小结

    1、Buffer缓冲区本质上是一个基础数据类型的数组,但又不仅仅是一个数组,它提供了高效地对数据的结构化访问,以及跟踪数据元素的读/写位置。

    2、对Buffer的读/写切换、清除、压缩等操作,在某种意义上来说,其实就是对数据元素索引值position、limit的操作。

    3、Buffer并没有提供直接删除数据元素的方法,而是只能覆盖。所以,当调用 / 方法后,只是重新设置了position、limit、mark的值,原来的数据还是在Buffer中的,在覆盖之前依然是可以读取到的。

    4、Buffer写满数据后,依然是可以继续写入的,只是需要设置写入的位置,并且写入新数据后原数据会被覆盖;同样,Buffer中的数据是可以重复读取的,只要调用 方法即可。(或者可指定索引位置读/写数据)

    5、Buffer可以比较大小,且比较时只会校验比较剩余元素。

    6、Buffer分配的最大容量创建时就固定了,不支持动态扩/缩容,Buffer的读/写模式切换也较为不便等等( 方法调用麻烦且易出错),这些也可以说是Buffer的不足之处。

  • 0
  • 0
  • 0
  • 10
  • 请登录之后再进行评论

    登录
  • 任务
  • 实时动态
  • 发布
  • 单栏布局 侧栏位置: