一 核心要素

  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;

NIO-BufferAPI的更多相关文章

  1. Java NIO(2):缓冲区基础

    缓冲区(Buffer)对象是面向块的I/O的基础,也是NIO的核心对象之一.在NIO中每一次I/O操作都离不开Buffer,每一次的读和写都是针对Buffer操作的.Buffer在实现上本质是一个数组 ...

  2. Java高并发网络编程(三)NIO

    从Java 1.4开始,Java提供了新的非阻塞IO操作API,用意是替代Java IO和Java Networking相关的API. NIO中有三个核心组件: Buffer缓冲区 Channel通道 ...

  3. 源码分析netty服务器创建过程vs java nio服务器创建

    1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...

  4. BIO\NIO\AIO记录

    IO操作可以分为3类:同步阻塞(BIO).同步非阻塞(NIO).异步(AIO). 同步阻塞(BIO):在此种方式下,用户线程发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后, ...

  5. 支撑Java NIO 与 NodeJS的底层技术

    支撑Java NIO 与 NodeJS的底层技术 众所周知在近几个版本的Java中增加了一些对Java NIO.NIO2的支持,与此同时NodeJS技术栈中最为人称道的优势之一就是其高性能IO,那么我 ...

  6. Java I/O and NIO [reproduced]

    Java I/O and NIO.2---Five ways to maximize Java NIO and NIO.2---Build more responsive Java applicati ...

  7. JAVA NIO学习笔记1 - 架构简介

    最近项目中遇到不少NIO相关知识,之前对这块接触得较少,算是我的一个盲区,打算花点时间学习,简单做一点个人学习总结. 简介 NIO(New IO)是JDK1.4以后推出的全新IO API,相比传统IO ...

  8. Java NIO概述

    Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然 Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Se ...

  9. JAVA NIO Socket通道

      DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...

  10. JAVA NIO FileChannel 内存映射文件

      文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...

随机推荐

  1. 基于Python接口自动化测试框架(初级篇)附源码

    引言 很多人都知道,目前市场上很多自动化测试工具,比如:Jmeter,Postman,TestLink等,还有一些自动化测试平台,那为啥还要开发接口自动化测试框架呢?相同之处就不说了,先说一下工具的局 ...

  2. Mac下怎么更新nodejs

    Windows下更新nodejs最简单粗暴的应该就是去官网下载安装包安装了,昨天项目中需要更新nodejs我便找了一下相关文章,发现有一个 n 模块可以管理node,n 是Node的一个模块,所以安装 ...

  3. 一道CTF针对XXE漏洞的练习

    题目链接:http://web.jarvisoj.com:9882/ 目的很明确获取/home/ctf/flag.txt的内容 一般读取目标机的本地文件都会用到file协议. 思路: 那么思路一:文件 ...

  4. 洛谷p1980 计数问题

    题目描述 试计算在区间 111 到 nn n的所有整数中,数字x(0≤x≤9) x(0 ≤ x ≤ 9)x(0≤x≤9)共出现了多少次?例如,在 111到11 11 11中,即在 1,2,3,4,5, ...

  5. Gin_渲染

    1. 各种数据响应格式 package main import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gi ...

  6. 为什么 RMAN 控制文件自动备份的名称格式没有遵循 %F 规则

    在 Oracle 中越是简单的问题,往往越难找到答案,举个例子: 你是否留意观察过在 RMAN 进行备份的时候,自动生成的控制文件名称是否是按照 %F 规则来生成的? 关于控制文件自动备份路径格式,在 ...

  7. for循环与闭包

    Es5 function box(){ var arr = []; ;i<;i++){ arr[i] = (function(num){ //自我执行,并传参(将匿名函数形成一个表达式)(传递一 ...

  8. Spring整合MyBatis案例练习笔记

    需求: 用户登录 技术需求: Servlet+Spring+Mybatis+MVC+jsp+css+html+jquery 数据库设计: 用户表 Sql语句设计: select * from t_us ...

  9. 巨杉内核笔记 | 会话(Session)

    SequoiaDB 巨杉数据库是一款金融级分布式关系型数据库,坚持从零开始打造分布式开源数据库引擎.“内核笔记系列”旨在分享交流 SequoiaDB 巨杉数据库引擎的设计思路和代码解析,帮助社区用户深 ...

  10. 简单易用,用Powershell劫持Windows系统快捷键

    POC:  $WshShell = New-Object -comObject WScript.Shell $Shortcut = $WshShell.CreateShortcut("des ...