JNI学习(二)

静态注册

接着上篇博客学习

JNI函数

 JNIEXPORT void JNICALL Java_com_example_jnidemo_TextDemo_setText
    (JNIEnv *env, jobject this, jstring string){
__android_log_print(ANDROID_LOG_ERROR, "test", "invoke set from C\n");
    char* str = (char*)(*env)->GetStringUTFChars(env,string,NULL);
    __android_log_print(ANDROID_LOG_ERROR, "test", "%s\n", str);
    (*env)->ReleaseStringUTFChars(env, string, str);
    }

JNI函数有两个关键字JNIEXPORT和JNICALL,这两个关键字是宏定义,主要用于说明该函数时JNI函数,在虚拟机加载so库时,如果发现函数含有上面两个宏定义时,就会链接到对应java层的native方法。
"extern c"是避免编译器按照C++的方式去编译C函数,原因是C不支持函数的重载,编译之后函数名不变。C++支持函数的重载(这点与java一致),编译之后函数名会改变

函数名

看到.c中的函数名字是"Java_com_example_jnidemo_TextDemo_setText"而在.java中定义的native函数名:setText,为什么对应到.c中函数名会变成这么长呢?
这跟JNI native函数的注册方式有关
JNI native函数有两种注册方式:
1、静态注册:按照JNI接口规范的命名规则注册
2、动态注册:在.cpp的JNI_OnLoad方法里注册
JNI接口规范的命名规则:
Java_PackageName_ClassName_MethodName
当我们在Java中调用native方法时,JVM也会根据这种命名规则来查找、调用native方法对应的C方法

JNIENV

JNIENV代表了Java环境,通过(*JNIEnv)就可以对Java端的代码进行操作比如:
1、创建Java的对象
2、调用Java对象的方法
3、获取java对象的属性等
我们可以通过jni.h查看可知:
在这里插入图片描述
在这里插入图片描述
JNIEnv指向_JNIEnv,而_JNIEnv是定义的一个C++结构体,里面包含了很多通过JNI接口对象调用的方法。

jobject

jobject代表了定义native函数的Java类或java类的实例:
1、如果native函数是static,则代表类Class对象
2、如果native函数是非static,则代表类的实例对象
我们可以通过jobject访问定义该native方法的成员方法、成员变量等。

java、JNI、C/C++数据类型映射关系

基本数据类型转化关系

在java中调用jni的native方法传递的参数是java类型的,这些参数必须经过Dalvik虚拟机转换成JNI类型的才能被JNI层所识别,如图
在这里插入图片描述

引用类型转换关系

JNI的引用类型定义了九种数组类型,以及jobject、jclass、jstring、jthrowable四种类型,它们的继承关系如下图:
在这里插入图片描述
它们与java类型的对应关系如下:
在这里插入图片描述

动态注册

动态注册的原理

直接告诉native函数其在JNI中对应函数的指针

动态注册的原理是这样的:JNI允许我们提供一个函数映射表,注册给JVM,这样JVM就可以用函数映射表来调用相应的函数,而不必通过函数名来查找相关函数(这个查找效率很低,函数名超级长)。
实现过程:
1、利用结构体JNINativeMethod保存Java Native函数和JNI函数的对应关系
2、在一个JNINativeMehod数组中保存所有native函数和JNI函数的对应关系
3、在Java中通过System.loadLibrary加载完JNI动态库后,调用JNI_OnLoad函数,开始动态注册
4、JNI_OnLoad中会调用(*env)->FindClass找到本地java类
5、JNI_OnLoad中调用(*env)->RegisterNatives函数进行函数注册

动态注册的步骤:
1、创建JNIDemo工程,编写java类,例如:MainActivity.java
2、build project 整个工程,在build\intermediates\javac\debug\classes\包名 文件下会生成MainActivity.class文件
3、在build\intermediates\javac\debug\classes 目录下打开命令行,输入 javah -jni 包名.MainActivity(全类名)生成包名MainActivity.h文件
4、在app目录下新建jni文件夹,在jin文件夹下创建register.c文件
5、编写register.c文件,并导入jni.h,包名_MainActivity.h头文件,重写JNI_OnLoad函数。

6、在register.c文件中创建JNINativeMethod数组,数组里面每一个元素JNI映射函数,这个我们后面会详细讲解。
7、在JNI_OnLoad函数里面需要完成以下四步:
- 通过(*vm)->GetEnv获取JVM的JNIEnv的属性信息
- 通过(*env)->FindClass方法找到对应的本地类
- 通过(*env)->RegisterNatives方法注册java本地类中的方法
- 通过return 返回值指定指定Jni版本

8、在jni文件夹下创建CMakeLists.txt文件,并在CMakeLists.txt文件中指定要生成的so库名称以及要使用的register.c源文件
9、在build.gradle文件中添加cmkeLists.text文件的路径,
10、运行so库。

JNINativeMethod

Android中使用了一种与传统不同的java JNI的方式的来定义其native的函数。
其中很重要的区别是Android使用了一种java和C函数的映射表数组,并在其中描述了函数的参数和返回值。这个数组的类型是JNINativeMethod,JNINativeMethod其实是一个结构体,在jni.h头文件中定义,通过这个结构体从而使java与jni建立联系,定义如下:

typedef struct {

const char* name; //Java中函数的名字

const char* signature;//符号签名,描述了函数的参数和返回值

void* fnPtr;//函数指针,指向一个被调用的函数

} JNINativeMethod;

  • 第一个变量name 是java中函数的名字
  • 第二个变量signature,是字段描述符(签名)或者函数描述符(签名)
  • 第三个变量fnotr是函数指针,指向C函数。Void*是万能指针,可以理解相当于java中的泛型
    下面我们重点讲一下第二个变量signature也就是签名。

签名

什么是签名

所谓函数签名,简单点的理解可以理解成一个函数的唯一标识,一个签名对应着一个函数的签名。这个是一一对应的关系。有些人可能会问:函数名不能作为标识吗?答案是否定的,因为java支持重载

为什么要有签名呢?

我们知道,java是支持函数重载的。一个类里面可以有多个同名但是不同参数的函数,所以函数名+参数名才能构成一个函数的表示,因此我们需要针对参数做一个签名标识。这样jni层才能唯一识别到这个函数。

如何获取函数的签名

函数的签名是针对函数的参数以及返回值进行组成的。它遵循如下格式(参数类型1;参数类型2;参数类型3…)返回值类型。
目前我知道获取签名的两种方式:1、生成的.h文件,对应函数上面的注释
2利用命令:javap -s -p TextDemo.class

基本数据类型签名对照表
类型标识                       Java类型
Z                             boolean
B                             byte
C                             char
S                             short
I                             int
J                             long
F                             float
D                             double
L/java/language/String        String
[I                            int[]
[Ljava/lang/object            Object[]
V                             void

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/262637.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【mongoose】 Model.create() no longer accepts a callback 报错解决

在最新版的 mongoose 操作 MongoDB 数据库的时候,当我们插入一条数据时候,会报错 :Model.create() no longer accepts a callback,看了很多文章都说是,版本太高,都妥协选择了降低回旧版本,但我就…

HotRC DS600遥控器+F-06A接收机

PWM原理说明 DS600遥控器说明 DS600遥控器的默认高电平是1.5ms 1通道 左右 2通道 前后 3通道 接管 上电后是1ms ,按一下是2ms,1ms和2ms切换 DS600接收机说明 */ #include "ps2.h" #include "common.h"#define LEFT_RIGHT_CHAN…

centos7安装开源日志系统graylog5.1.2

安装包链接:链接:https://pan.baidu.com/s/1Zl5s7x1zMWpuKfaePy0gPg?pwd1eup 提取码:1eup 这里采用的shell脚本安装,脚本如下: 先使用命令产生2个参数代入到脚本中: 使用pwgen生成password_secret密码 …

数据库——事务

智能2112杨阳 一、目的与要求: 1.熟悉提交事务 2.回滚事务 3.检查点技术 注:可以用可视化软件来实现 二、内容: 基于现有数据库设计事务提交、事务回滚、及检查点实验,观察比较提交前后执行结果并分析。 源码&#xff1a…

管控品牌价格就是在维护品牌价值

当品牌各渠道中存在低价、乱价链接时,品牌首先应针对这些低价链接的不同现状进行管控,使链接不再低价,或者被下架删除链接,这些就是有效的价格管控流程,品牌价格被稳定住,也是在维护和稳定品牌价值。 品牌价…

Vue表格中鼠标移入移出input显示隐藏 ,有输入值不再隐藏

Vue表格中鼠标移入移出input显示隐藏 , 不再隐藏的效果 <el-tableref"table":data"tableDatas"borderstyle"width: 100%":span-method"arraySpanMethod"id"table"row-key"id"cell-mouse-enter"editCell&q…

mysql主从复制(在虚拟机centos的docker下)

1.安装docker Docker安装(CentOS)简单使用-CSDN博客 2.部署2个mysql docker run --name some-mysql1 -p 33061:3306 -e MYSQL_ROOT_PASSWORD123456 -d mysql:5.7 --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_cidocker run --name some-mysql2 -p 330…

Ubuntu 常用命令之 chown 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 chown 命令在 Ubuntu 系统中用于改变文件或目录的所有者和组。这个命令的基本格式是 chown [选项]... [所有者][:[组]] 文件...。 chown 命令的主要参数有 -c 或 --changes&#xff1a;类似 verbose&#xff0c;但只在发生改变时…

智能DJ软件Algoriddim djay Pro AI mac功能特点

Algoriddim djay Pro AI mac是一款具有人工智能功能的 DJ 软件&#xff0c;它可以让 DJ 在演出时更加灵活、创意和自由。 Algoriddim djay Pro AI mac主要特点 人工智能智能排列功能&#xff1a;djay Pro AI 可以根据 BPM、音调和热度等因素&#xff0c;将曲目按照最优顺序排列…

护眼台灯适合考公用吗?高口碑的护眼台灯分享

护眼台灯近年来受到越来越多人的关注和喜爱&#xff0c;还得到了一些知名博主、眼科专家和学生家长的认可和推荐&#xff0c;但是市场上存在着一些劣质产品&#xff0c;这些产品存在光线不均、频闪等问题&#xff0c;长期使用这些低劣护眼台灯可能还会导致眼睛酸痛等不适情况。…

vue:antV | G6的超级详细使用(包括基本使用、示例使用、自定义节点以及增删改查功能的灵活应用)

目录 第一章 理解基本信息 1.1 安装与引入 1.2 了解基本使用 1.2.1 创建容器 1.2.2 节点信息 1.2.3 边信息 1.2.4 图配置 1.2.5 渲染图数据 1.2.6 demo源代码 1.2.7 实现效果 第二章 g6图表示例使用 2.1 示例代码的展及解释 2.2 示例效果 第三章 自定义图demo及…

python编程(1)之通用引脚GPIO使用

在之前的章节中&#xff0c;小编带领大家学习了&#xff1a;如何构建esp32的python开发环境-CSDN博客 今天小编带领大家开始学习python编程的第一节&#xff0c;通用引脚。esp32c3核心板是一个高度集成&#xff0c;功能丰富的模块&#xff0c;来看下他的功能分布&#xff1a; 我…

『Linux升级路』基础开发工具——gdb篇

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;Linux &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、背景知识介绍 二、gdb指令介绍 一、背景知识介绍 在软件开发中&#xff0c…

不要再浪费时间,一键获取SolidWorks,设计革命由此开始!

不要再在网上浪费时间寻找SolidWorks的安装包了&#xff0c;一键下载安装&#xff0c;你要的一切都可以在这里找到&#xff01; 对于3D建模和计算机辅助设计的人来说&#xff0c;SolidWorks是一个不可或缺的工具。然而&#xff0c;在网上寻找合法且可靠的软件安装包却常常让人…

「工业遥测」图表控件LightningChart在水工业中的应用

LightningChart.NET完全由GPU加速&#xff0c;并且性能经过优化&#xff0c;可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D&#xff0c;高级3D&#xff0c;Polar&#xff0c;Smith&#xff0c;3D饼/甜甜圈&#xff0c;地理地图和GIS图表以及适用于科学…

nuxt打包占用磁盘IO

目录 前言排除过程 前言 jenkins运行打包&#xff0c;总是要卡一段时间&#xff0c;磁盘IO很高。我手动执行后的确发现了这个问题&#xff0c;如下图所示。 排除过程 我的方案很原始&#xff0c;利用git恢复到以前的版本&#xff0c;抽检&#xff0c;搞了差不多两个小时&am…

es、MySQL 深度分页问题

文章目录 es 深度分页MySQL 深度分页 es 深度分页 es 深度分页问题&#xff0c;有点忘记了&#xff0c;这里记录一下 当索引库中有10w条数据&#xff0c;比如是商品数据&#xff1b;用户就是要查在1w到后10条数据&#xff0c;怎么查询。 es查询是从各个分片中取出前1w到后10条数…

【SpringBoot篇】解决缓存击穿问题① — 基于互斥锁方式

文章目录 &#x1f339;什么是缓存击穿&#x1f33a;基于互斥锁解决问题&#x1f6f8;思路 &#x1f3f3;️‍&#x1f308;代码实现 &#x1f339;什么是缓存击穿 缓存击穿是指在使用缓存系统时&#xff0c;对一个热点数据的高并发请求导致缓存失效&#xff0c;多个请求同时访…

JavaOOP篇----第十篇

系列文章目录 文章目录 系列文章目录前言一、构造方法能不能显式调用?二、什么是方法重载?三、构造方法能不能重写?能不能重载?四、内部类与静态内部类的区别?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,…

软件工程快速复习(期末急救)

每个同学要假想自己是一个项目经理&#xff0c;去完成一个软件项目&#xff0c;比如医院管理系统&#xff0c;自动设备控制系统等&#xff0c;以面向结构的软件工程方法&#xff0c;说出完成项目的步骤&#xff0c;涉及到的具体技术。初步了解面向对象的方法的与面向结构的方法…