Java NIO系列知识(二) Buffer

学习笔记,个人理解,如有错误劳烦指正,谢谢!

Buffer(缓冲区)作为java nio的三大核心组件之一 ,担任和数据直接打交道的任务,任何数据需要传输都必须储存在Buffer中。它本质上是一块可以写入数据,然后可以从中读取数据的内存,并提供了一系列方法,用来方便的访问该块内存。

Buffer的分类

Buffer是一个用于储存特定基本类型数据的容器,为了应对各种数据类型,java.nio.*中为它提供了多种(包括但不限于以下七个)实现类用于扩展它的功能。

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

这些Buffer类型代表了不同的数据类型。换句话说,就是可以通过charshortintlongfloatdouble类型来操作缓冲区中的数据,其中ByteBuffer是最常用实现类

Buffer的核心属性

查看Buffer的源码,发现有如下四个属性。

// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;

对于新创建的Buffer对象实例,四个属性的大小关系:mark <= position <= limit <= capacity

Buffer提供了以上四个核心属性,以方便操作所包含的数据

  • capacity容量
    • 缓冲区能够容纳的数据元素的最大数量。容量在缓冲区刚创建时被设定,其不能为负并且不能改变。(不能被改变的原因是因为底层是数组)
  • limit上限
    • 缓冲区里的数据的总数,代表了当前缓冲区中总共储存了多少数据。
  • position位置
    • 下一个要被读或写的元素的位置position会自动由相应的 get( )和 `put( )方法更新。
  • mark标记
    • 执行mark()操作时,记录当前的读写位置,相当于一个存档,初始值为-1
Buffer的基本用法

使用Buffer读写数据一般遵循以下五个步骤:

  1. 创建一个指定大小的Buffer
  2. Buffer中写入数据
  3. 调用flip()方法,由写模式转换为读模式
  4. Buffer中读取数据
  5. 调用clear()或者compact()方法
代码演示

下面展示一下Buffer的读写过程,以及四个核心属性在读写过程中的变化

package cn.lincain.nio.buffer;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;

public class BufferDemo {
	public static void main(String[] args) throws Exception {
		
		// 1. 创建一个容量为20的buffer
		ByteBuffer buffer = ByteBuffer.allocate(20);
		// 通过反射获取ByteBuffer下私有属性
		Field field = ByteBuffer.class.getSuperclass().getDeclaredField("mark");
        field.setAccessible(true);
		
		// 新创建时,4个核心变量的值
        System.out.println("初始时-->limit--->"+buffer.limit());
        System.out.println("初始时-->position--->"+buffer.position());
        System.out.println("初始时-->capacity--->"+buffer.capacity());
        System.out.println("标记前-->mark--->" + (Integer) field.get(buffer));
        System.out.println("标记时-->mark--->" + buffer.mark());
        System.out.println("标记后-->mark--->" + (Integer) field.get(buffer));
        System.out.println("--------------------------------------");

        // 2 .添加一些数据到缓冲区中
        String s = "byteBuffer";
        buffer.put(s.getBytes());

        // 写入数据后,4个核心变量的值
        System.out.println("put完之后-->limit--->"+buffer.limit());
        System.out.println("put完之后-->position--->"+buffer.position());
        System.out.println("put完之后-->capacity--->"+buffer.capacity());
        System.out.println("标记前-->mark--->" + (Integer) field.get(buffer));
        System.out.println("标记时-->mark--->" + buffer.mark());
        System.out.println("标记后-->mark--->" + (Integer) field.get(buffer));
        System.out.println("--------------------------------------");
        
        // 3 .调用flip()方法,由写模式转换为读模式
        buffer.flip();
        // 转换状态后,4个核心变量的值
        System.out.println("flip完之后-->limit--->"+buffer.limit());
        System.out.println("flip完之后-->position--->"+buffer.position());
        System.out.println("flip完之后-->capacity--->"+buffer.capacity());
        System.out.println("标记前-->mark--->" + (Integer) field.get(buffer));
        System.out.println("标记时-->mark--->" + buffer.mark());
        System.out.println("标记后-->mark--->" + (Integer) field.get(buffer));
        System.out.println("--------------------------------------");
        
        // 4. 从缓冲区中读取一个数据
        char ch = (char) buffer.get();
        System.out.println("读取的数据:" + ch);
        // 从缓冲区读取一个数据后,4个核心变量的值
        System.out.println("get完之后-->limit--->"+buffer.limit());
        System.out.println("get完之后-->position--->"+buffer.position());
        System.out.println("get完之后-->capacity--->"+buffer.capacity());
        System.out.println("标记前-->mark--->" + (Integer) field.get(buffer));
        System.out.println("标记时-->mark--->" + buffer.mark());
        System.out.println("标记后-->mark--->" + (Integer) field.get(buffer));
        System.out.println("--------------------------------------");
        
        // 5.执行clear()方法
        buffer.clear();
        System.out.println("clear完之后-->limit--->"+buffer.limit());
        System.out.println("clear完之后-->position--->"+buffer.position());
        System.out.println("clear完之后-->capacity--->"+buffer.capacity());
        System.out.println("标记前-->mark--->" + (Integer) field.get(buffer));
        System.out.println("标记时-->mark--->" + buffer.mark());
        System.out.println("标记后-->mark--->" + (Integer) field.get(buffer));
        System.out.println("--------------------------------------");
        
        // 遍历buffer,其中的数据依然存在,并没有真正的删除
        for (int i = 0; i < 10; i++) {
        	System.out.print((char)buffer.get(i));
		}
	}
}

执行以上代码,得到的结果如下:

初始时-->limit--->20
初始时-->position--->0
初始时-->capacity--->20
标记前-->mark--->-1
标记时-->mark--->java.nio.HeapByteBuffer[pos=0 lim=20 cap=20]
标记后-->mark--->0
--------------------------------------
put完之后-->limit--->20
put完之后-->position--->10
put完之后-->capacity--->20
标记前-->mark--->0
标记时-->mark--->java.nio.HeapByteBuffer[pos=10 lim=20 cap=20]
标记后-->mark--->10
--------------------------------------
flip完之后-->limit--->10
flip完之后-->position--->0
flip完之后-->capacity--->20
标记前-->mark--->-1
标记时-->mark--->java.nio.HeapByteBuffer[pos=0 lim=10 cap=20]
标记后-->mark--->0
--------------------------------------
读取的数据:b
get完之后-->limit--->10
get完之后-->position--->1
get完之后-->capacity--->20
标记前-->mark--->0
标记时-->mark--->java.nio.HeapByteBuffer[pos=1 lim=10 cap=20]
标记后-->mark--->1
--------------------------------------
clear完之后-->limit--->20
clear完之后-->position--->0
clear完之后-->capacity--->20
标记前-->mark--->-1
标记时-->mark--->java.nio.HeapByteBuffer[pos=0 lim=20 cap=20]
标记后-->mark--->0
--------------------------------------
byteBuffer

在这里插入图片描述

结论

根据上述结果,得出如下结论:

  • 创建buffer实例对象后,capcity的值将不会改变。
  • putget操作会自动更新position的值
  • flipclear操作会将position归零,以及将mark归为-1
  • putclear操作不会删除buffer中的数据
  • mark记录的是调用mark()方法时,当前position的值,方便后续操作

上面的代码没有对compact()方法进行演示,单独说一下compact操作会将还未读取的数据复制到buffer的头部,后面的数据保持不变,以上面的btyeBuffer为例,如果get()了一个字符后,执行compact()方法,buffer中的数据就变成了tyeBufferr,数据的总量并没有发生变化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值