Java NIO中的缓冲区Buffer(一)缓冲区基础
什么是缓冲区(Buffer)
定义
简单地说就是一块存储区域,哈哈哈,可能太简单了,或者可以换种说法,从代码的角度来讲(可以查看JDK中Buffer、ByteBuffer、DoubleBuffer等的源码),Buffer类内部其实就是一个基本数据类型的数组,以及对这个缓冲数组的各种操作;
常见的缓冲区如ByteBuffer、IntBuffer、DoubleBuffer...内部对应的数组依次是byte、int、double...
与通道的关系
在Java NIO中,缓冲区主要是跟通道(Channel)打交道,数据总是从缓冲区写入到通道中,或者从通道读取数据到缓冲区;
继承结构
关于Buffer的继承结构,我们可以简单的以ByteBuffer为例,如下:
Buffer是顶层抽象类,ByteBuffer继承Buffer,也是抽象类,ByteBuffer最常见的两个具体实现类如下:
DirectByteBuffer(JVM堆外部、通过unsafe.allocateMemory实现)、HeapByteBuffer(JVM堆)
缓冲区的四个属性(capacity、limit、position、mark)
容量(capacity)
capacity指的是缓冲区能够容纳元素的最大数量,这个值在缓冲区创建时被设定,而且不能够改变,如下,我们创建了一个最大容量为10的字节缓冲区;
ByteBuffer bf = ByteBuffer.allocate(10);
上界(limit)
limit指的是缓冲区中第一个不能读写的元素的数组下标索引,也可以认为是缓冲区中实际元素的数量;
位置(position)
position指的是下一个要被读写的元素的数组下标索引,该值会随get()和put()的调用自动更新;
标记(mark)
一个备忘位置,调用mark()方法的话,mark值将存储当前position的值,等下次调用reset()方法时,会设定position的值为之前的标记值;
四个属性值之间的关系
根据以上四个属性的定义,我们可以总结出它们之间的关系如下:
0 <= mark <= position <= limit <= capacity
举个例子,观察四个属性值的变化
1、创建一个容量大小为10的字符缓冲区
ByteBuffer bf = ByteBuffer.allocate(10);
此时:mark = -1; position = 0; limit = 10; capacity = 10;
2、往缓冲区中put()五个字节
bf.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'0');
注意这里一个字符是占用两个字节的,但是英文字符只占用一个字节,所以这样是可以实现储存效果的;
此时:mark = -1; position = 5; limit = 10; capacity = 10;
3、调用flip()方法,切换为读就绪状态
bf.flip();
此时:mark = -1; position = 0; limit = 5; capacity = 10;
4、读取两个元素
System.out.println("" + (char) bf.get() + (char) bf.get());
此时:mark = -1; position = 2; limit = 5; capacity = 10;
5、标记此时的position位置
bf.mark();
此时:mark = 2; position = 2; limit = 5; capacity = 10;
6、读取两个元素后,恢复到之前mark的位置处
System.out.println("" + (char) bf.get() + (char) bf.get());
bf.reset();
属性变化情况:
执行完第一行代码:mark = 2; position = 4; limit = 5; capacity = 10;
执行完第二行代码:mark = 2; position = 2; limit = 5; capacity = 10;
7、调用compact()方法,释放已读数据的空间,准备重新填充缓存区
bf.compact();
此时:mark = 2; position = 3; limit = 10; capacity = 10;
注意观察数组中元素的变化,实际上进行了数组拷贝,抛弃了已读字节元素,保留了未读字节元素;
缓冲区比较
其实查看equals源码就可以知道是如何比较的,如下(以ByteBuffer为例):
public boolean equals(Object ob) {
if (this == ob)
return true;
if (!(ob instanceof ByteBuffer))
return false;
ByteBuffer that = (ByteBuffer)ob;
if (this.remaining() != that.remaining())
return false;
int p = this.position();
for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
if (!equals(this.get(i), that.get(j)))
return false;
return true;
}
总的来说,两个缓冲区被认为相等的条件如下(以下内容直接摘自《Java NIO》):
- 两个对象类型相同。包含不同数据类型的 buffer 永远不会相等,而且 buffer绝不会等于非 buffer 对象。
- 两个对象都剩余同样数量的元素。Buffer 的容量不需要相同,而且缓冲区中剩余数据的索引也不必相同。但每个缓冲区中剩余元素的数目(从位置到上界)必须相同。
- 在每个缓冲区中应被 Get()方法返回的剩余数据元素序列必须一致。
批量读写缓冲区数据
以ByteBuffer为例,使用如下API即可:
public ByteBuffer get(byte[] dst, int offset, int length)
public ByteBuffer put(byte[] src, int offset, int length)
public ByteBuffer get(byte[] dst)
public final ByteBuffer put(byte[] src)
实际上,后面两种方法内部就是调用前面两种方法的;
参数的含义直接查看源码注释即可,写的很清楚,如put(byte[] src, int offset, int length)方法的注释:
/* @param src
* The array from which bytes are to be read
*
* @param offset
* The offset within the array of the first byte to be read;
* must be non-negative and no larger than <tt>array.length</tt>
*
* @param length
* The number of bytes to be read from the given array;
* must be non-negative and no larger than
* <tt>array.length - offset</tt>
*/
参考资料
《Java NIO》
Java NIO中的缓冲区Buffer(一)缓冲区基础的更多相关文章
- Java NIO入门(二):缓冲区内部细节
Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...
- Java NIO中的Buffer 详解
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的.缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...
- java NIO中的buffer和channel
缓冲区(Buffer):一,在 Java NIO 中负责数据的存取.缓冲区就是数组.用于存储不同数据类型的数据 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区:ByteBufferC ...
- JAVA NIO学习笔记二 频道和缓冲区
Java NIO 频道 Java NIO渠道类似于流,他们之间具有一些区别的: 您可以读取和写入频道.流通常是单向(读或写). 通道可以异步读取和写入数据. 通道常常是读取或写入缓冲区. 如上所述,您 ...
- 转:Java NIO系列教程(三) Buffer
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...
- Java NIO中核心组成和IO区别
1.Java NIO核心组件 Java NIO中有很多类和组件,包括Channel,Buffer 和 Selector 构成了核心的API.其它组件如Pipe和FileLock是与三个核心组件共同使用 ...
- Java NIO(三) Buffer
Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的. 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...
- java输入输出 -- java NIO之缓存区Buffer
一.简介 java NIO相关类在jdk1.4被引入,用于提高I/O的效率.java NIO包含很多东西,但核心的东西不外乎Buffer.channel和selector.本文先来看Buffer的实现 ...
- 转载Java NIO中的Files类的使用
Java NIO中的Files类(java.nio.file.Files)提供了多种操作文件系统中文件的方法. Files.exists() Files.exits()方法用来检查给定的Path在文件 ...
随机推荐
- uboot——git代码仓
1,注册GitHub帐号,创建GitHub项目代码仓库 https://www.cnblogs.com/LoTGu/p/6075994.html 参考其第二段,注册账号,设置仓库. 2,上传代码 测试 ...
- PHP开发——数组
数组的概念 l 数组是一组数的集合.如:$arr = array(1,2,3,4,5,6) l 标量数据类型是一个值的容器,而数组就是多个值的容器. 数组的分类 l 枚举数组:数组元素的下标(索 ...
- robotframework手机号随机产生脚本
首先,要导入使用库 random; ${phone} Evaluate random.choice(['139','188','185','136','158','151'])+"" ...
- BootStrap常用组件及响应式开发
BootStrap常用组件 PS:所有的代码必须写在<class="container/container-fluid">容器当中 常用组件包含内容: 字体图标 下拉菜 ...
- Linux anaconda 内网 安装 卸载
安装并不难, 官网介绍的很清楚, 但每次到官网找安装方法不方便,我总结了本文(很全) 官网下载Linux版anaconda, 地址https://www.anaconda.com/download/# ...
- Java WEB开发环境搭建以及创建Maven Web项目
根据此链接博文学习配置: http://www.cnblogs.com/zyw-205520/p/4767633.html 1.JDK的安装 自行百度,(最好是jdk1.7版本的) 测试如下图,即完成 ...
- 2019.03.01 bzoj2555: SubString(sam+lct)
传送门 题意简述: 要求在线支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 思路: 考虑用lctlctlct来动态维护samsa ...
- hdu 1069 Monkey and Banana 【动态规划】
题目 题意:研究人员要测试猴子的IQ,将香蕉挂到一定高度,给猴子一些不同大小的箱子,箱子数量不限,让猩猩通过叠长方体来够到香蕉. 现在给你N种长方体, 要求:位于上面的长方体的长和宽 要小于 下面 ...
- 长方体类Java编程题
1. 编程创建一个Box类(长方体),在Box类中定义三个变量,分别表示长方体的长(length).宽(width)和高(heigth),再定义一个方法void setBox(int l, int w ...
- js-实时获取键值码
<script> document.onkeydown=function(event){ console.log(event.keyCode) //在控制台打印 } </scr ...