Java NIO之Buffer详细理解

Vue项目实战:用DataV的dv-scroll-board打造高颜值滚动表格(附完整代码) 本文详细介绍了如何在Vue项目中使用DataV的dv-scroll-board组件打造高颜值滚动表格。从基础集成到高级配置,包括动态数据处理、深度样式定制、性能优化策略以及交互增强方案,帮助开发者快速实现企业级数据展示需求。特别针对样式优化和滚动表格的常见问题提供了实用解决方案。 阅读详情

Buffer简介

Buffer:是一个指定特定数据类型的容器,主要用于和Channel进行数据交互。在多线程操作下 Buffer 是不安全的。

 

在Java NIO中使用的核心缓冲区如下(覆盖了通过I/O发送的基本数据类型:byte, char、short, int, long, float, double, long):

ByteBuffer

CharBuffer

ShortBuffer

IntBuffer

FloatBuffer

DoubleBuffer

LongBuffer

 

Buffer的基本属性

capacity(容量) :缓冲区能够容纳的数据元素的最大数量。

limit(界限):缓冲区中第一个不能读或写的元素位置

position(位置):下一个读或写的元素的索引。位置会随着get()和put()函数更新

mark(标记):标记一个备忘的位置

以上四个属性的关系:

mark <= position <= limit <= capacity

 

Buffer使用

接下来以最常用的ByteBuffer为例进行介绍

1.创建Buffer对象

  public static ByteBuffer allocate(int capacity)  //静态方法,通过内存分配创建Buffer对象

  public static ByteBuffer wrap(byte[] array)   //静态方法,将[]byte包装成ByteBuffer对象

  public static ByteBuffer wrap(byte[] array,int offset, int length) //基本同上,但指定了初始位置和长度

  public static ByteBuffer allocateDirect(int capacity) //通过分配直接缓冲区创建Buffer对象

 

  非直接缓冲区:通过allocate()分配缓冲区,将缓冲区建立在JVM的内存中

  直接缓冲区:通过allocateDirect()分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率。

内核地址空间和用户地址空间之间形成了一个物理内存映射文件,减少了内核到用户空间的copy过程

  public abstract boolean isDirect()  //可以通过该方法判断是否是直接缓冲区

  

  

2.读写常用的方法

在Buffer中有两种模式,一种是写模式,一种是读模式。

  put()相关函数:向ByteBuffer中添加元素(byte,[]byte,ByteBuffer等)

  flip()函数:将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。

  get():从Buffer中读取元素

  hasRemaining():判断Buffer中是否还有元素可读

  clear():清空元素

  compact():压缩元素(扩展空间)

 

利用Buffer读写数据,通常遵循四个步骤:

调用put()把数据写入buffer;

调用flip()从写模式切换成读模式;

调用get()从Buffer中读取数据;

调用buffer.clear()或者buffer.compact() 清除元素

 

Buffer源码

   构造器

    //构造函数,根据指定的参数来初始化Buffer特定的属性

    //此构造函数是包私有的

    Buffer(int mark, int pos, int lim, int cap) {       // package-private

        if (cap < 0)

            throw new IllegalArgumentException("Negative capacity: " + cap);

        this.capacity = cap;

        limit(lim);

        position(pos);

        if (mark >= 0) {

            if (mark > pos)

                throw new IllegalArgumentException("mark > position: ("

                                                   + mark + " > " + pos + ")");

            this.mark = mark;

        }

   }

构造器中使用了两个方法limit()和position()

     函数的功能:设置Buffer的limit,如果position大于newLimit,则将position设置为新的limit。

    如果mark被定义且大于新的limit,则就会被抛弃。

    public final Buffer limit(int newLimit) {

        //有效性检查,即limit必须满足这样的关系:0<=limit<=position.

        if ((newLimit > capacity) || (newLimit < 0))

            throw new IllegalArgumentException();

        limit = newLimit;

        //如果position大于newLimit,则将position设置为新的limit。

        if (position > limit) position = limit;

        //如果mark被定义且大于新的limit,则会被抛弃(即设置为-1)

        if (mark > limit) mark = -1;

        return this;

    }

    

   函数功能:设置Buffer的position.如果mark被定义且大于new position,则就会被抛弃。   

    public final Buffer position(int newPosition) {

        //有效性检查,即0<=newPosition<=limit.

        if ((newPosition > limit) || (newPosition < 0))

            throw new IllegalArgumentException();

        position = newPosition;

        //如果mark被定义且大于new position,则就会被抛弃。

        if (mark > position) mark = -1;

        return this;

    }

   

allocate()方法

    由于Buffer类是一个抽象类,是不可以实例化对象的,因此在Buffer中是不存在allocate(int cap)方法的,allocate(int cap)方法在其子类中均有实现。这里就以IntBuffer为例,看下Buffer子类IntBuffer的allocate(int cap)方法。

    public static IntBuffer allocate(int capacity) {
    
        if (capacity < 0)

            throw new IllegalArgumentException();

        return new HeapIntBuffer(capacity, capacity);

    }

    

函数功能:分配一个新的用来装载int类型数据的Buffer对象实例。这个new buffer的position为0,limit为capacity,mark为未定义的(即为-1)。buffer中的元素全部初始化为零。

 

在allocate方法中直接是实例化了一个IntBuffer子类的对象。

 

既然这里涉及要HeapIntBuffer类,我们就看下这个类

    public abstract class IntBuffer extends Buffer  implements Comparable<IntBuffer>

    class HeapIntBuffer  extends IntBuffer 

从继承关系我们知道:HeapIntBuffer这个类是IntBuffer的子类

 

这个类的构造函数为

    HeapIntBuffer(int cap, int lim) {            // package-private

        super(-1, 0, lim, cap, new int[cap], 0);

    }

在这个构造函数中直接调用了父类IntBuffer中对应的构造函数。看下IntBuffer类中的这个构造函数。

 

在看构造函数之前,这里要说下IntBuffer类中的几个属性。

    final int[] hb;                  // Non-null only for heap buffers

    final int offset;

    boolean isReadOnly;                 // Valid only for heap buffers

IntBuffer类中主要包括一个int类型的数组,即从这里我们知道,Buffer类的底层数据结构是借助于数组来完成的。

 

继续看IntBuffer类的构造方法

    // Creates a new buffer with the given mark, position, limit, capacity,
    // backing array, and array offset
    IntBuffer(int mark, int pos, int lim, int cap,   // package-private
                 int[] hb, int offset)
    {
        super(mark, pos, lim, cap);//调用父类Buffer中对应有参的构造函数
        this.hb = hb;
        this.offset = offset;
    }

  

以上,就是当我们使用如下代码得到IntBuffer实例的整个过程。

IntBuffer buffer = IntBuffer.allocate(cap);

 

2、put(int i)方法介绍

下面来看IntBuffer类中的put方法

    public abstract IntBuffer put(int i);

    public abstract int get(int index);

 

在IntBuffer类中put、get方法都是抽象的。

有了上面allocate方法的过程分析,我们知道IntBuffer buffer = IntBuffer.allocate(cap)

中的buffer实际上是父类的引用指向的是子类的对象。当我们使用buffer.put(value)/buffer.get().

实际上是调用子类HeapIntBuffer类中的put/get方法,这就是多态。在Java中相当重要的一个特征。

 

HeapIntBuffer类中put方法的实现如下:

    public IntBuffer put(int x) {
        hb[ix(nextPutIndex())] = x;
        return this;
    }

put方法实现的思想就是:将值存储在position位置即可。

 

这里涉及到两个新的函数,分别为:

1、nextPutIndex(),函数功能:简单来说就是返回下一个要写入元素的索引位置(即当前position值),并将position进行加一操作。

2、ix(int i):偏移offset个位置

这两个函数的实现如下:

  //函数功能:首先检查当前的position是否小于limit,如果小于则存储,否则抛异常。
    final int nextPutIndex() {                          // package-private
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }

    //函数功能:偏移offset个位置
    protected int ix(int i) { 
        return i + offset;
    }


  

3、get()方法介绍

看完了put方法,接下来来看下get方法

 

函数的功能:取得Buffer中position位置所指向的元素。

  //函数功能:获取buffer中position所指向的元素。
    public int get() {
        return hb[ix(nextGetIndex())];
    }

    //函数功能:获取buffer中索引为i位置的元素
    public int get(int i) {
        return hb[ix(checkIndex(i))];
    }

 


  

在get()方法中也涉及到两个另外的函数:

1、nextGetIndex(),函数功能:返回下一个读取的元素的索引位置(即position值)

2、ix(int i)

    final int nextGetIndex() {                          // package-private
        if (position >= limit)
            throw new BufferUnderflowException();
        return position++;
    }

    //将position向右移动nb个位置,这个函数目前还没有看见在哪里得到的应用
    final int nextGetIndex(int nb) {                    // package-private
        if (limit - position < nb)
            throw new BufferUnderflowException();
        int p = position;
        position += nb;
        return p;
    }

   

以上就是get方法的内部实现,也相当简单哈。

 

4、flip()方法介绍

其实,在刚开始看别人博客的时候,是最不能理解这个函数的功能的,疑问在于:为什么要在读Buffer中的内容时,要先调用这个方法呢。

 

其实在自己把Buffer的读模式和写模式弄清楚之后,这个函数的功能我也就明白了。


     //函数功能:将Buffer从写模式转化为读模式。
     //具体为:将limit设置为此时position并且将position设置为零。如果mark被定义了则被抛弃(即设置为-1)
     //这个方法的应用场景为:在管道读或调用put方法之后,调用此方法来为管道写或者是get操作做准备。
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

  

以上就是flip()方法的介绍,是不是也比较简单哈。

 

5、hasRemaining()介绍

函数功能:判断Buffer中是否还有可读取的元素。

    public final boolean hasRemaining() {
        return position < limit;
    }  

此方法的内部实现直接是判断position是否小于limit.

所以,逻辑也是相当简单的。

 

6、clear() compact()方法的介绍

clear()函数功能:清空Buffer中所有的元素。

 

其内部实现直接是将Buffer里面几个属性进行了重置。
  

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

最后看下compact方法

compact()方法的功能:将已读元素进行清除,未读元素拷贝保留并拷贝到Buffer最开始位置。这个也是和clear()方法不同的地方。

具体实现如下:

    public IntBuffer compact() {
        //先进行拷贝,即将剩余的没有访问的元素拷贝到Buffer从零开始的位置
        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());//remaining()函数返回的是剩余元素个数
        //设置position为下一个写入元素的位置
        position(remaining());
        //设置limit为Buffer容量
        limit(capacity());
        discardMark();//废弃mark,即将mark设置为-1
        return this;
    }



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

  


  

 

以上内容主要参考

《Java NIO》

https://blog.youkuaiyun.com/u010412719/article/details/52775637

https://blog.youkuaiyun.com/u010853261/article/details/53464397

https://www.cnblogs.com/KKSJS/p/9909587.html

https://www.cnblogs.com/snailclimb/p/Buffer.html

 

 

 

open3d将某一时间序列下的彩色图和深度图批量转换成点云(python) 必备条件需要3D相机生成的彩色图及深度图,注意要将深度图与彩色图对齐(一般3D相机自带对齐算子),以及3D相机的彩色图内参(相机自带内参获取功能)。有了此彩色图、对齐后的深度图以及相机内参就能使用open3d生成彩色点云了. 阅读详情

相关推荐

最新扣子(coze)案例:在coze上用DeepSeek+私有数据库、知识库,创建你的专属智能体

Gartner预测,到2026年,70%的企业将通过Al知识库实现「组织记忆外化」。数字化时代,数据已成为企业发展的核心资产。我们通过人工智能将知识库从“静态存储"升级为“智能服务”。让"沉睡宝藏"焕发新生,助力企业突破数据困局。

weixin_72689845的博客 2166

深入理解ByteBuffer

ByteBuffer类是在Java NIO中常常使用的一个缓冲区类,使用它可以进行高效的IO操作,但是,如果对常用方法的理解有错误,那么就会出现意想不到的bug。

东方吹雪的专栏 1万+

绕过卡巴斯基通过RPC控制lsass注入DLL

参考国外的XPN以及3gstudent大佬的文章: https://blog.youkuaiyun.com/xiangshen1990/article/details/104872566 https://gist.github.com/xpn/93f2b75bf086baf2c388b2ddd50fb5d0 原理:正常的ssp扩展(dll)可以加载到lsass进程中去,比如kerberos验证都是通...

2ed 3525

Java NIO ———— Buffer 缓冲区详解

引言 缓冲区是一个用于特定基本类型的容器。由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类。 Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互。数据从通道存入缓冲区,从缓冲区取出到通道中。 一、创建缓冲区 缓冲区的本质是数组,用于存储不同类型的数据,根据数据类型(boolean 除外),提供了相应类型的缓冲区,如ByteBuffer、In...

Morty的技术乐园 2450

天池长期赛:二手车价格预测(422方案分享)

本次比赛是一次很好的锻炼数据挖掘能力的入门赛,从EDA-数据清洗-特征工程-模型调参-模型融合,能够完整的学习到大数据的分析和挖掘,值得历练。

weixin_46685991的博客 1万+

【GD32篇】驱动AD7616完成数据采集

GD32F10X驱动AD7616完成数据采集

we_long的博客 1万+

ByteBuffer详解

一、前言 前一篇文章我们介绍了Android中直播视频技术的基础大纲知识,这里就开始一一讲解各个知识点,首先主要来看一下视频直播中的一个重要的基础核心类:ByteBuffer,这个类看上去都知道了,是字节缓冲区处理字节的,这个类的功能非常强大,也在各个场景都有用到,比如网络数据底层处理,特别是结合网络通道信息处理的时候,还有就是后面要说到的OpenGL技术也要用到,当然在视频处理中也是很重要

一场人生,一场梦 1万+

130页5万字某市档案馆数字档案馆建设方案

【版权声明】本资料来源网络,仅用于行业知识分享,供个人学习参考,请勿商用。【侵删致歉】如有侵权请联系小编,将在收到信息后第一时间进行删除!完整资料领取见文末,部分资料内容:国家档案局证实颁布《数字档案馆建设指南》, 明确了数字档案馆建设原则、要求、目标,对相关系统建设内容、功能要求进行了概括和详细说明。数字档案馆系统建设应以 OAIS&nbsp;参考模型为设计基础,以实现数字资源的长期保存与可信管理。设计的数字档案馆系统架构如下图。图-1 数字档案馆体系结构数字档案馆建设包括五大层次和三大保障体系:

zuoan1993的博客 1182

Java NIO学习篇之缓冲区Buffer详解

定义 缓冲区Buffer在java nio中负责数据的存储,缓冲区就是数组,用于存储不同类型数据的数组。 jdk为java七大基本类型数据都准备了响应的缓冲区(boolean值除外): ByteBuffer CharBuffer ShortBuffer IntegerBuffer LongBuffer FloatBuffer DoubleBuffer 上述缓冲区除了ByteBuffer的 功能稍微多点外,因为ByteBuffer是通用的,所以功能会比较多。其他6种的使用方式几乎是一致的。 /* * Bu

qq_40837310的博客 1069

使用 PLS 回归进行近红外光谱的异常值检测

在光谱数据中,并非每个数据点都是有效的,因此,在构建模型时找到与大部分数据不符合的数据点是一种必要的操作。这些数据我们称之为。在这篇文章中,我们将使用PLS回归进行红外光谱数据的异常值检测。

qq_44204759的博客 1424

STM32F407最小系统硬件设计与CubeMX工程实践

嵌入式最小系统是MCU功能实现的物理基础,其核心涵盖供电网络、时钟架构、复位机制与调试接口四大模块。基于Cortex-M4内核的STM32F407对电源纹波、晶振稳定性及信号完整性提出严苛要求:模拟电源VDDA需<10mV纹波,HSE晶振布线须满足短距直连与匹配电容精准配置,SWD调试接口依赖50Ω阻抗控制与端接防护。这些硬件约束直接映射至STM32CubeMX配置——如RCC时钟树参数必须与实物晶振频率严格一致,GPIO模式需匹配外设电气特性(如I2C必选开漏),否则将引发通信失败或启动异常。典型应用场景

weixin_35592186的博客 173

Java NIO基本组件Buffer详解

Buffer组件 对数据读取、写入要用buffer,本质就是一个数组 Buffer最常用的类 Buffer缓冲区状态变量 mark(标记):标记position位置 position(位置):当前读写的位置 limit(上界):缓冲区现存元素的计数 capacity(容量):最大容量 0 <= mark <= position <= limit <= capacity 写入缓冲区 写入一个字节,position移动1格,position就是当前写入位置 读取缓冲区 调用bu

weixin_44371237的博客 860

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java NIO理解(三)Buffer

缓冲区分类  NIO中的buffer用于和通道交互,数据是从通道读入缓冲区,从缓冲区中写入通道的。Buffer就像一个数组,可以保存多个类型相同的数据。每种基本数据类型都有对应的Buffer类: 缓冲区的属性 1、capacity(容量):buffer本质是一个数组,在初始化时有固定的大小,这个值就是容量。容量不可改变,一旦缓冲区满了,需要将其清空才能将继续进行读写操作。 2、position(...

热心网友 272

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JAVA NIO Buffer理解(一)

JAVA NIO buffer Buffer的使用总结如下: 先把数据写入Buffer,buffer的 write mode 方式一 channel.read(buffer) 数据从channel读入buffer 方式二 buffer.put(bytes) 数据写入buffer 从Buffer中读取数据,buffer的 read mode buffer的读和写模式需注意limit limit在r...

刘滨浩的博客 1195

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

buffer java nio_Java NIO深入理解Buffer(缓冲区)

前言Github:https://github.com/yihonglei/java-allProject:java-nio一 Buffer概述Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。二 B...

weixin_36099614的博客 253

java nio buffer 理解

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34117522的博客 122

Java NIO中Buffer常用方法的用法及理解

一、首先,什么是Buffer? Buffer,中文意思就是缓冲区,一个用于特定基本类型的容器,由java.nio提供该类,及以下常用子类: ByteBuffer CharBuffer ShortBufer IntBuffer LongBuffer FloatBuffer DoubleBuffer,并没有BooleanBuffer.      二、其次,这么多的buffer,它的作用是什么呢?

有灯就可以编程的博客 5057

理解java.nio.buffer

NIO包(java.nio.*)引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题。 1. Buffer:它是包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作。 2. Charset:它提供Unicode字符串影射到字节序列以及逆影射的操...

chimu9074的博客 163

NIO学习(七):Java NIO的Buffer的scattering和gathering理解

背景 scatting和gathering研究的是一个buffer数组。在这个buffer数组中持有多个Buffer实例,每个Buffer都是独立的,都有自己独立的capacity,limit,position值。 buffer数组中的buffer实例唯一相互联系的地方就是:从第一个buffer数组中的Buffer实例开始,依次读满后才往后面的Buffer实例移动。写也是如此。从数组中的第一个B...

sanding的博客 492

Java NIO 三大核心(Buffer、Channel、Selector)理解

NIO 三大核心(Buffer、Channel、Selector)

在路上 1098

NIO学习(六):Java NIO的Buffer属性(capacity,position,limit,mark)理解

背景 Java NIO中提供了7种基础数据类型的Buffer,分别是:ByteBuffer, CharBuffer,ShortBuffer, LongBuffer, FloatBuffer, DoubleBuffer,它们都继承抽象类Buffer。 抽象类Buffer的底层就是装字节的容器(字节数组容器)。 Buffer有3个很重要的属性,capactiy, position,limit。 当b...

sanding的博客 1229

[Java]java中对NIO缓冲区(Buffer)的理解

//缓冲区(Buffer):在java NIO中负责数据的存取。缓冲区就是数组。用于存储不同类型的数据 /* 一、根据数据类型的不同(boolean除外),提供了相应类型的缓冲区: ByteBuffer CharBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区 二、缓冲区存取数据的2个核心方法 put():存入数据到缓

mmmm0584的博客 190

图解Java NIO Buffer

Buffer四个基本属性 1、capacity:能够容纳的最大元素数目,创建时设定并不能更改 2、limit: buffer中有效位置数目 3、position: 下一个读或者写的位置 4、mark: 用于记忆的标志位,配合reset()使用,初始值未设定,调用mark后将当前position设为值 标记、位置、限制和容量值有以下关系: 0 <= 标记 <= 位置 <= 限制 <= 容量

I am not a quitter. 1436

Java NIO(三)NIO之Buffer

系列文章目录 第一篇 Java NIO(一)I/O简介 第一篇 Java NIO(二)BIO 第一篇 Java NIO(三)NIO之Buffer 第一篇 Java NIO(四)NIO之Channel 第一篇 Java NIO(五)NIO之Selector 第一篇 Java NIO(六)Netty) Java NIO(三)NIO之Buffer 目录系列文章目录Java NIO(三)NIO之Buffer前言一、示例代码二、Buffer1. 介绍2. Buffer分类3. Buffer的基本原理4. Buffe

Devinskx的博客 321

Java NIO之缓冲区Buffer学习------(看完别说不理解)

一、Buffer是啥? 一个用于特定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类 Java NIO 中的 Buffer 主要用于与 NIO 通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。 二、 Buffer的子类 千言万语胜不过一图 从图知除boolean 外,基本数据类型都有缓冲区 三、缓冲区的基本属性 Buffer 中的重要...

qiukui111的博客 454

Java-NIO(2)

Java-NIO(2) 缓冲区 常规I/O操作存在很大缺点,主要是因为它们是阻塞的,而NIO正是为了解决常规I/O执行效率低的问题,采用非阻塞高性能运行的方式来避免出现笨拙的同步I/O带来的效率低的问题 缓冲区Buffer,在NIO的使用中地位很高,因为数据就是放到缓冲区,对数据进行处理的 NIO中的Buffer是一个用于存储基本数据类型的容器,它以类似于数组有序的方式来存储和组织数据,每个基本数...

Coder_py的博客 395
上一篇: Java线程池详细理解
下一篇: Java NIO之Channel详细理解
思维的深度
博客等级 码龄11年 2万+粉丝 391原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值