当前位置: 首页 > news >正文

NDK(三):JNIEnv解析

文章目录

  • 一、概述
  • 二、JNIEnv结构体
  • 三、JNINativeInterface结构体
    • 3.1 Class操作
    • 3.2 反射操作
    • 3.3 对象字段 & 方法操作
    • 3.4 类的静态字段 & 静态方法操作
    • 3.5 字符串操作
    • 3.6 锁操作
    • 3.7 数组操作
    • 3.8 注册和反注册native方法
    • 3.9 异常Exception操作
    • 3.10 引用的操作
    • 3.11 其它
  • 四、小结

一、概述

JNIEnv(Java Native Interface Environment) 是一个JNI接口指针 (每个线程独有一个 JNIEnv 指针),指向了本地方法的一个函数表,该函数表中的每一个成员指向了一个JNI函数,本地的方法通过JNI函数来访问JVM中的数据结构,详情如下图:

在这里插入图片描述

关联文章:

  • NDK(一):NDK的集成
  • NDK(二):JNI的数据结构
  • NDK(三):JNIEnv解析
  • NDK(四):Native与Java层互调
  • NDK(五):JNI静态注册与动态注册

参考文章:

  • JNI Functions 官方文档

二、JNIEnv结构体

我们知道 JNI 方法一般都是使用 JNIEnv 去调用,而 JNIEnv 又是一个指针,所以JNI中有哪些函数,只需要找到 JNIEnv 的实现体就可以了。

struct _JNIEnv;
# C中直接使用JNINativeInterface指针进行操作。
typedef const struct JNINativeInterface* C_JNIEnv; #if defined(__cplusplus)
typedef _JNIEnv JNIEnv;

从上述代码可以看到,C中直接使用 JNINativeInterface 指针进行操作。在C++文件中是对_JNIEnv 起的一个别名 JNIEnv。

下面我们来看下 _JNIEnv 结构体的定义。

struct _JNIEnv {/* do not rename this; it does not seem to be entirely opaque */const struct JNINativeInterface* functions;#if defined(__cplusplus)jint GetVersion(){ return functions->GetVersion(this); }jclass DefineClass(const char *name, jobject loader, const jbyte* buf,jsize bufLen){ return functions->DefineClass(this, name, loader, buf, bufLen); }jclass FindClass(const char* name){ return functions->FindClass(this, name); }// ...略
}

通过上面的代码可知,_JNIEnv 内部所有的操作都是委托给JNINativeInterface指针进行操作的,相当于_JNIEnv只是一个代理层。而在C语言中直接使用的是JNINativeInterface指针,这就是JNIEnv在C和C++调用方式不一致的原因。

三、JNINativeInterface结构体

下面我们来分析一下 JNINativeInterface 的结构体,JNINativeInterface 结构体中主要包含如下几类的操作:

  • Class操作
  • 反射操作
  • 对象字段 & 方法操作
  • 类的静态字段 & 静态方法操作
  • 字符串操作
  • 锁操作
  • 数组操作
  • 注册和反注册native方法
  • 异常Exception操作
  • 引用的操作

下文中 JNINativeInterface 内的方法有时会省略一些参数信息,我们可以通过 JNI Functions 官方文档 来查看函数原型。

以 FindClass 函数为例:

struct JNINativeInterface {jclass      (*FindClass)(JNIEnv*, const char*);
}// 函数原型为:
jclass FindClass(JNIEnv *env, const char *name);

详情如下图所示:

在这里插入图片描述

3.1 Class操作

struct JNINativeInterface {/*获取当前JNI版本信息:*/jint 	(*GetVersion)(JNIEnv *);// 定义一个类:类是从某个字节数组buf中读取出来的jclass  (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*, jsize);// 查找全限定名为name的类:如String类:"java/lang/String"jclass 	(*FindClass)(JNIEnv*, const char*);// 获取当前类的父类:通常在使用FindClass获取到类之后,再调用这个函数jclass	(*GetSuperclass)(JNIEnv*, jclass);
}

3.2 反射操作

struct JNINativeInterface {// 将一个Method对象转换为jmethodIDjmethodID   (*FromReflectedMethod)(JNIEnv*, jobject);jfieldID    (*FromReflectedField)(JNIEnv*, jobject);// 通过jmethodID,反射得到Method对象jobject     (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);/* spec doesn't show jboolean parameter */jobject     (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);
}

3.3 对象字段 & 方法操作

struct JNINativeInterface {// 通过指定jclass类名、字段名称、字段类型来获取jfieldIDjfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);// ---------- 操作Field -------------// 通过类的jobject和jfieldID获取字段的jobject对象。void        (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);// 8种基本类型字段的获取与赋值。void        (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);jbyte       (*GetByteField)(JNIEnv*, jobject, jfieldID);// ---------- 操作Method -------------// 通过指定jclass类名、方法名称、方法签名信息来获取jmethodIDjmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);// 8种基本类型:boolean、byte、char、short、int、long、float、double。// ...是可变长度的参数,参数类型相同。jbyte       (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);// va_list是可变长度的参数,参数类型可以不同。jbyte       (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);// jvalue 是8中基本类型jbyte       (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, const jvalue*);	
}typedef union jvalue {jboolean    z;jbyte       b;jchar       c;jshort      s;jint        i;jlong       j;jfloat      f;jdouble     d;jobject     l;
} jvalue;

小结:

  • 方法参数通过支持3种不同的参数类型来覆盖所有的参数场景。
  • 单个参数场景:使用 jvalue 来表示支持一个参数的场景。
  • 多个相同参数场景:使用 … 来表示支持同类型的多个参数。
  • 多个不同参数场景:使用 va_list 来表示支持不同类型的多个参数。

3.4 类的静态字段 & 静态方法操作

struct JNINativeInterface {// ---------- 操作 Static Field -------------                        jfieldID    (*GetStaticFieldID)(JNIEnv*, jclass, const char*, const char*);void        (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);jobject     (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);void        (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);jbyte       (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);// ---------- 操作 Static Method -------------// 与GetMethodID方法类似。jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);// 三种参数方式:...、va_list、jvalue。jbyte       (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);jbyte       (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);jbyte       (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, const jvalue*);
}

3.5 字符串操作

struct JNINativeInterface {jstring     (*NewString)(JNIEnv*, const jchar*, jsize);jsize       (*GetStringLength)(JNIEnv*, jstring);const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);void        (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);jstring     (*NewStringUTF)(JNIEnv*, const char*);jsize       (*GetStringUTFLength)(JNIEnv*, jstring);/* JNI spec says this returns const jbyte*, but that's inconsistent */const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);void        (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);
}

3.6 锁操作

struct JNINativeInterface {jint        (*MonitorEnter)(JNIEnv*, jobject);jint        (*MonitorExit)(JNIEnv*, jobject);
}

3.7 数组操作

struct JNINativeInterface {jbyteArray  (*NewByteArray)(JNIEnv*, jsize);jbyte*      (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);void        (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray, jbyte*, jint);void        (*SetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, const jbyte*);void        (*GetByteArrayRegion)(JNIEnv*, jbyteArray, jsize, jsize, jbyte*);
}

3.8 注册和反注册native方法

struct JNINativeInterface {jint        (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*, jint);jint        (*UnregisterNatives)(JNIEnv*, jclass);
}

动态注册JNI代码时会使用 RegisterNatives 函数。具体请参考 - NDK(五):JNI静态注册与动态注册

3.9 异常Exception操作

struct JNINativeInterface {jint        (*Throw)(JNIEnv*, jthrowable);jint        (*ThrowNew)(JNIEnv *, jclass, const char *);jthrowable  (*ExceptionOccurred)(JNIEnv*);void        (*ExceptionDescribe)(JNIEnv*);void        (*ExceptionClear)(JNIEnv*);void        (*FatalError)(JNIEnv*, const char*);
}

3.10 引用的操作

struct JNINativeInterface {// 全局变量的创建与删除jobject     (*NewGlobalRef)(JNIEnv*, jobject);void        (*DeleteGlobalRef)(JNIEnv*, jobject);// 局部变量的创建与删除jobject     (*NewLocalRef)(JNIEnv*, jobject);void        (*DeleteLocalRef)(JNIEnv*, jobject);// 对象的比较jboolean    (*IsSameObject)(JNIEnv*, jobject, jobject);}

3.11 其它

struct JNINativeInterface {jint        (*GetJavaVM)(JNIEnv*, JavaVM**);jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);jint        (*PushLocalFrame)(JNIEnv*, jint);jobject     (*PopLocalFrame)(JNIEnv*, jobject);
}

四、小结

  • JNIEnv 是一个代理,实际的操作全部委托给 JNINativeInterface 指针执行。
  • JNINativeInterface 结构体中主要包含如下几类的操作:
    • Class操作
    • 反射操作
    • 对象字段 & 方法操作
    • 类的静态字段 & 静态方法操作
    • 字符串操作
    • 锁操作
    • 数组操作
    • 注册和反注册native方法
    • 异常Exception操作
    • 引用的操作

相关文章:

NDK(三):JNIEnv解析

文章目录一、概述二、JNIEnv结构体三、JNINativeInterface结构体3.1 Class操作3.2 反射操作3.3 对象字段 & 方法操作3.4 类的静态字段 & 静态方法操作3.5 字符串操作3.6 锁操作3.7 数组操作3.8 注册和反注册native方法3.9 异常Exception操作3.10 引用的操作3.11 其它四…...

禅道——图文安装及使用教程

👨‍💻作者简介:练习时长两年半的java博主 📖个人主页:君临๑ 🎞️文章介绍:禅道的2023版安装图文教程 🎁 如果文章对你有用,就点个免费的赞吧👍 目录 一、搜…...

Java基础——枚举类enum

枚举类是一种特殊的数据类型,可以理解为一个数组,数组成员为特定的对象枚举类不能在外面创建对象,在类里面就包含了一组特定的对象,每个对象有着相同数量的属性枚举类的对象放在最前面,且对象们的顺序就是对应的索引枚…...

【机器学习】一文了解如何评估和选择最佳机器学习模型并绘制ROC曲线?

一文了解如何评估和选择最佳机器学习模型? 问ChatGPT:如何选择最佳机器学习模型?问ChatGPT:评估机器学习模型有哪些指标?0. 引言1. 混淆矩阵2. 评价指标3. ROC与AUC4. PR(precision recall )曲线参考资料问ChatGPT:如何选择最佳机器学习模型? 选择最佳机器学习模型是机…...

vue3 笔记

watchEffect 的起源 stackoverflow - watchEffect vs. watch watch behavior in v3 is different to v2Change watch Options API to trigger immediately vue3 最初只有 watch ,没有 watchEffect。这个时候的 watch 默认是 immediate true,可以 wat…...

第12章_MySQL数据类型精讲

第12章_MySQL数据类型精讲 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生&#xff0c…...

二叉树路径总和第一题

1题目 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。 叶子节点 是指没有…...

@RefreshScope源码解析

前言 RefeshScope这个注解想必大家都用过,在微服务配置中心的场景下经常出现,它可以用来刷新Bean中的属性配置,那么它是如何做到的呢?让我们来一步步揭开它神秘的面纱。 RefreshScope介绍 就是说我们在修改了bean属性的时候项目…...

【开发】后端框架——Spring

前置知识:JSP&Servlet 学习视频:https://www.bilibili.com/video/BV1WE411d7Dv?spm_id_from333.999.0.0 IoC:控制反转 IoC的理解:IoC思想,IoC怎么创建对象,IoC是Spring的核心 依赖注入三种方式&#x…...

vue中的自定义指令

前言 说到 vue 中的自定义指令,相信大家都不陌生。在官网中是这么说的,除了核心功能默认内置的指令 (v-model 和 v-show),vue 也允许注册自定义指令。那什么时候会用到自定义指令呢?代码复用和抽象的主要形式是组件。然而&#xf…...

技术分享及探讨

前言 很高兴给大家做一个技术分享及探讨。 下面给大家分享几个工作遇到有趣的例子。 docker docker 进程 现象 ​ 客户的模型导入到BML平台发布预测服务后,模型本身是用django提供的支持。按照本地docker的方式进行调试,kill掉django的进程修改代码…...

人工智能AI

AI 模型。它使用深度神经网络,从数十亿或数万亿个单词中学习,能够生成任何主题或领域的文本。它可以执行各种自然语言任务,如分类、总结、翻译、生成和对话。 大语言模型开发建立在4个核心思想上: 模型 – Models 提示词 - Prompt…...

2022天梯赛补题

题目详情 - L2-041 插松枝 (pintia.cn) 思路:模拟 背包就是个栈,开个stack解决流程思路是,每次取推进器前,尽可能拿背包的,背包拿到不可以时,跳出拿推进器时判断: 如果背包装得下,…...

字节跳动测试岗面试挂在2面,复盘后,我总结了失败原因,决定再战一次...

先说下我基本情况,本科不是计算机专业,现在是学通信,然后做图像处理,可能面试官看我不是科班出身没有问太多计算机相关的问题,因为第一次找工作,字节的游戏专场又是最早开始的,就投递了&#xf…...

Nodejs实现通用的加密和哈希算法(MD5、SHA1、Hmac、AES、Diffie-Hellman、RSA),crypto模块详解

crypto crypto模块的目的是为了提供通用的加密和哈希算法(hash)。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。 MD5和SHA1 MD5是一种常用的哈希算法,…...

测试行业3年经验,从大厂裸辞后,面试阿里、字节全都一面挂,被面试官说我的水平还不如应届生

测试员可以先在大厂镀金,以后去中小厂毫无压力,基本不会被卡,事实果真如此吗?但是在我身上却是给了我很大一巴掌... 所谓大厂镀金只是不卡简历而已,如果面试答得稀烂,人家根本不会要你。况且要不是大厂出来…...

安卓悬浮窗口,  丝滑双指缩放视频窗口

最重要的事情说前面: demo源码:https://github.com/5800LDW/ProjectFloatingWindow前言:1.跨应用的浮动窗口在网上很多资料, 就不细说了。2.双指缩放View 也很多资料, 可参考:https://blog.csdn.net/zxq614/article/details/88873729正文下面进入正题, 如何把上述结合起来, 下面…...

300左右哪款蓝牙耳机适合学生用?四款便宜质量好的蓝牙耳机推荐

近年来,随着蓝牙耳机的发展,不管是音质、外观、佩戴还是降噪都有了很大的提升。但是我们在入手蓝牙耳机时,最好还是根据预算和需求入手。在此,我来给预算在三百内的朋友推荐几款便宜质量好的蓝牙耳机,可以当个参考。 …...

桥梁设计模式

介绍 Java桥梁模式(也称桥接模式)(Bridge Pattern)是一种设计模式,它将抽象和实现分离,使它们可以独立地变化.它通过一个大类或者一系列紧密关联的类拆分成两个独立的层次结构来实现这种分离,其中一个层次结构包含抽象类或接口,另一个层次结构包含实现类.桥梁模式使得抽象类和…...

【华为OD机试 2023最新 】 新员工座位(C++)

文章目录 题目描述输入描述输出描述用例题目解析C++题目描述 工位由序列F1,F2…Fn组成,Fi值为0、1或2。其中0代表空置,1代表有人,2代表障碍物。 1、某一空位的友好度为左右连续老员工数之和, 2、为方便新员工学习求助,优先安排友好度高的空位, 给出工位序列,求所有空…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...