当前位置: 首页 > 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、为方便新员工学习求助,优先安排友好度高的空位, 给出工位序列,求所有空…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

如何为服务器生成TLS证书

TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

Go语言多线程问题

打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...