Buffer是个啥?

Buffer 即缓冲区,用来暂存输入输出数据的区域。Buffer对象是一份固定数量的数据的容器,实质上是一个数组。但是一个缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问,还可以跟踪系统的读/写进程。
 
在 Java传统 IO 中,数据直接写入或者将数据直接读到 Stream 对象中。
而在 NIO 中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,都是将它放到缓冲区中。
NIO中的Buffer主要用于与NIO通道(channel)进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。
 

继承关系图

Buffer作为一个容器用来存储数据的,根据存储数据类型的不同,分为以下七种:
ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer

主要属性

// 标记、位置、限制、容量遵守以下不变式:
// 0<=mark<=position<=limit<=capacity // 标记是一个位置索引,可以在之后设置位置为标记值再次读写。
private int mark = -1; // 位置,表示缓冲区中正在操作数据的位置。
// 可以把position理解成一个指针,指向的位置就是操作的位置。
private int position = 0; // 界限,表示缓冲区中可以操作数据的大小。
private int limit; // 容量,表示缓冲区中最大存储数据的容量。一旦声明,不可改变。
private int capacity; // 指向缓冲区的地址
long address;

构造方法

// 创建一个具有给定标记、位置、限制和容量的新缓冲区
Buffer(int mark, int pos, int lim, int cap) {
// 缓冲区的初始化容量不能小于0
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
// 初始化缓冲区容量
this.capacity = cap;
// 初始化缓冲区限制,设置最新的缓冲区Buffer
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("
+ mark + " > " + pos + ")");
this.mark = mark;
}
}

关键方法解析

position方法:设置当前操作位置

public final Buffer position(int newPosition) {
// 当前操作位置不能超过limit大小,不能小于0
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
// 如果标记位置大于正在操作位置,那么将mark设置为-1。
if (mark > position) mark = -1;
return this;
}

limit方法:设置缓冲区限制

public final Buffer limit(int newLimit) {
// newLimit大小不能超过缓冲区最大容量capacity,不能小于0
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
// 正在操作数据的位置不能大于界限
if (position > limit) position = limit;
// 如果标记位置大于界限,那么将mark设置为-1。
if (mark > limit) mark = -1;
return this;
}

reset方法:将缓冲区Buffer的位置position设置为以前临时备忘变量mark存储的位置

public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
clear方法:清除缓冲区,clear方法并没有将之前的数据真的清除,当读数据前调用flip方法后,limit会限制不让使用旧数据。
public final Buffer clear() {
position = 0;
// 虽然将limit数值设置为最大容量,只是为了正常使用buffer
limit = capacity;
mark = -1;
return this;
}

flip方法: 反转此缓冲区,在进行写完去读的时候使用,说白了,让你开始读的时候从初始位置0开始。

public final Buffer flip() {
// 将position置为0,其实就是切换读写模式
limit = position;
position = 0;
mark = -1;
return this;
}

rewind方法:重绕此缓冲区,在通道写入或者获取之前调用

public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}

remaining方法:返回当前的缓冲区Buffer中剩余元素的数量

public final int remaining() {
return limit - position;
}

总结

1、Buffer中所有的方法操作,都遵守以下不变式:
 0<=mark<=position<=limit<=capacity
2、flip方法,让数据开始读的时候从初始位置0开始。
3、clear方法其实是个障眼法,并没有清除之前数据内容。

盘一盘 NIO (一)—— Buffer源码解析的更多相关文章

  1. Git8.3k星,十万字Android主流开源框架源码解析,必须盘

    为什么读源码 很多人一定和我一样的感受:源码在工作中有用吗?用处大吗?很长一段时间内我也有这样的疑问,认为哪些有事没事扯源码的人就是在装,只是为了提高他们的逼格而已. 那为什么我还要读源码呢?一刚开始 ...

  2. Python优秀开源项目Rich源码解析

    这篇文章对优秀的开源项目Rich的源码进行解析,OMG,盘他.为什么建议阅读源码,有两个原因,第一,单纯学语言很难在实践中灵活应用,通过阅读源码可以看到每个知识点的运用场景,印象会更深,以后写代码的时 ...

  3. Scala 深入浅出实战经典 第65讲:Scala中隐式转换内幕揭秘、最佳实践及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...

  5. Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  7. Netty 4源码解析:服务端启动

    Netty 4源码解析:服务端启动 1.基础知识 1.1 Netty 4示例 因为Netty 5还处于测试版,所以选择了目前比较稳定的Netty 4作为学习对象.而且5.0的变化也不像4.0这么大,好 ...

  8. Netty5客户端源码解析

    Netty5客户端源码解析 今天来分析下netty5的客户端源码,示例代码如下: import io.netty.bootstrap.Bootstrap; import io.netty.channe ...

  9. Netty5服务端源码解析

    Netty5源码解析 今天让我来总结下netty5的服务端代码. 服务端(ServerBootstrap) 示例代码如下: import io.netty.bootstrap.ServerBootst ...

随机推荐

  1. Orleans 知多少 | 2. 核心概念一览

    Orleans 术语解读 上面这张图中包含了Orleans中的几个核心概念: Grain Silo Orleans Cluster Orleans Client 从这张图,我们应该能理清他们之间的关系 ...

  2. C#3.0新增功能09 LINQ 标准查询运算符 02 查询表达式语法

    连载目录    [已更新最新开发文章,点击查看详细] 某些使用更频繁的标准查询运算符具有专用的 C# 语言关键字语法,使用这些语法可以在查询表达式中调用这些运算符. 查询表达式是比基于方法的等效项更具 ...

  3. sql注入篇2

    一.前言 上一篇:sql注入篇1 二.基于回显的注入类型判断 1.有结果的注入 例如下图: (sqlllab less-1)可以看到有正常结果返回,对于的利用方式就是老套路了,先order by查询出 ...

  4. Python识别璇玑图中诗的数量

    一.璇玑图简介 璇玑图的读法有很多,这里我使用七七棋盘格的读法,在璇玑图中分离出一个七七棋盘格,如下表 吏 官 同 流 污 合 玩 痞 悍 蒙 骗 造 假 蛋 鸡 宴 请 客 友 朋 远 戚 偏 正 ...

  5. [学习笔记] MySQL入门

    一.MySQL的安装与简单使用 ubuntu16.04下安装MySQL: sudo apt-get update sudo apt-get install mysql-server mysql-cli ...

  6. 计时器(Chronometer)、标签(TabHost)

    计时器(Chronometer) 方法 描述 public Chronometer(Context context)[构造方法] 创建Chronometer对象 public long getBase ...

  7. 2019前端面试系列——HTTP、浏览器面试题

    浏览器存储的方式有哪些 特性 cookie localStorage sessionStorage indexedDB 数据生命周期 一般由服务器生成,可以设置过期时间 除非被清理,否则一直存在 页面 ...

  8. Java | Map排序,工具类改进

    package util; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; ...

  9. 数据结构之堆栈java版

    import java.lang.reflect.Array; /* 具体原理在c++版已经说的很清楚,这里不再赘述, 就提一点:java的泛型具有边界效应,一旦离开作用域立马被替换为object类型 ...

  10. macos Mojave 出现网络出错 Frame Check Sequence: Bad checksum

    问题描述:使用软电话外呼的时候出现Request Timeout . 端口监听之后通过 Wireshark发现错误:`Frame Check Sequence: Bad checksum`,查看wir ...