JNI学习(二)

news2024/12/27 3:35:14

静态注册

接着上篇博客学习

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日一题——链表的回文结构

链表的回文结构 1. 题目描述 对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。 给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。 测试…

SpringBoot集成swagger-ui

1.引入依赖&#xff1a; <!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version></dependency><dependency><groupId>io.sprin…

回归预测 | MATLAB实现GWO-DHKELM基于灰狼算法优化深度混合核极限学习机的数据回归预测 (多指标,多图)

回归预测 | MATLAB实现GWO-DHKELM基于灰狼算法优化深度混合核极限学习机的数据回归预测 &#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现GWO-DHKELM基于灰狼算法优化深度混合核极限学习机的数据回归预测 &#xff08;多指标&#xff0c;多图&#…

查找算法——二分查找

笔记&#xff1a;二分查找算法 | 数据结构与算法 系列教程&#xff08;笔记&#xff09; 题目描述 请对一个 有序数组 进行二分查找 {1,8, 10, 89, 1000, 1234}&#xff0c;输入一个数看看该数组是否存在此数&#xff0c;并且求出下 标&#xff0c;如果没有就提示「没有这个数…

前端ICON库

前端ICON库 1.mingcute mingcute 2.lordicon lordicon 3.字节iconpark&#xff08;推荐&#xff09; 字节iconpark 4.iconbuddy iconbuddy.app/ 5.商标寻找youicons 免费下载数百万个徽标以获得设计灵感 | YouIcons.com 还有一堆工具

一键转换,将HTML智能转换为PDF,轻松解决文档转换需求

在数字时代&#xff0c;HTML网页是我们获取信息的主要来源之一。然而&#xff0c;有时候我们可能需要将网页内容以PDF格式保存&#xff0c;以便于离线阅读、打印或分享。这时&#xff0c;将HTML转换为PDF就变得尤为重要。 首先&#xff0c;我们要进入首助编辑高手主页面&#x…

华为数通方向HCIP-DataCom H12-831题库(多选题:181-200)

第181题 如图所示,R1、R2、R3、R4都部署为SPF区域0,链路的cost值如图中标识。R1、R2R3、R4的Loopback0通告入OSPF。R1、R2、R3与R4使用Loopback0作为连接接口,建立BGP对等体关系,其中R4为RR设备,R1、R2、R3是R4的客户端。当R4的直连地址172.20,1,4/32通告入BGP后,以下关R…

单细胞转录组揭示杨树维管组织结构与发育

之前我们有一篇PC的文章&#xff0c;专门介绍了通过单细胞转录组分析杨树茎中初生和次生生长组织中形成层细胞分化的分子轨迹&#xff08;文章回顾&#xff1a;植物单细胞转录组 | 杨树初生生长和次生生长中形成层细胞分化的分子轨迹&#xff09;。2023年发表于《Molecular Pla…

mysql区分度不高的字段建索引一定没用吗?

建立索引的目的是提高数据库查询的性能&#xff0c;通过索引可以快速定位到符合查询条件的数据。然而&#xff0c;对于区分度不高的字段来说&#xff0c;建立索引可能会带来一些问题。 当字段的区分度很低时&#xff0c;即字段中的唯一值或不同值的数量相对较少&#xff0c;建立…

AI代码翻译神器,用AI翻译代码,轻松学习不同编程语言,已开源!

体验地址&#xff0c;github地址和部署地址在文章底部 AI代码翻译器的优势 近年来&#xff0c;随着技术的快速进步&#xff0c;人工智能技术展现出了在各个领域发挥作用的巨大潜力。AI代码翻译器作为一项创新技术&#xff0c;为开发者带来了全新的可能性。这项技术运用人工智…

FreeSWITCH 1.10 源码阅读(7)-uuid_bridge 命令原理解析

文章目录 1. uuid_bridge 命令执行2. 源码分析3. uuid_bridge 问题处理 1. uuid_bridge 命令执行 uuid_bridge 命令用于将两条腿桥接在一起&#xff0c;以实现双方的通话。下图是该命令在 FreeSWITCH 中的处理流程&#xff0c;大致的流程可以分成以下几个步骤&#xff1a; uui…

图像分割与修复

图像分割的方法 &#xff08;1&#xff09;传统的图像分割方法 &#xff08;2&#xff09;基于深度学习的图像分割方法 传统的图像分割方法 &#xff08;1&#xff09;分水岭法 &#xff08;2&#xff09;GrabCut法 &#xff08;3&#xff09;MeanShift法 &#xff08;4…

Linux调试器gdb的用法

Linux调试器gdb的用法 1. debug/release版本之间的比较2. gdb调试器的基本指令3. 使用展示 1. debug/release版本之间的比较 在之前学习C语言的的时候出过一期vs的调试技巧。 而对于现在的Linux下的调试器gdb其实也是换汤不换药的&#xff0c;基本上的调试思路是不会改变的&am…

Electron Vite打包后,部分图标未显示的解决方案

背景 这个问题&#xff0c;弄了一晚上&#xff0c;头都大了&#xff0c;找了一堆博客也没解决。主要参考这个&#xff1a;https://blog.csdn.net/m0_73845616/article/details/129741099。 下面讲一下我的解决方案。 解决方案 上面链接里的方法&#xff0c;我采用第二、三个都…

鸿蒙-arkTs:访问控制授权申请

module.json5文件中 requestPermissions 进行配置&#xff08;值为数组&#xff0c;可配置多个&#xff09; ohos.permission.INTERNET {"name": "ohos.permission.INTERNET" }

鸿蒙-HarmonyOS之初见

鸿蒙初识&#xff0c;此事能成&#xff01;&#xff01; 自己安装工具、配置环境并运行成功&#xff0c;流程记录。 一、首先官网下载开发工具 官网地址&#xff1a;https://developer.huawei.com/consumer/cn/ 当前最新的版本3.1 &#xff0c;windows和Mac&#xff0c;Mac又…

GD32移植STM32工程(因为懒,所以移植)

文章目录 一、前言二、差异性三、软件移植部分1.前期准备1.1 安装GD32固件库1.2 选择所用芯片 2.修改程序2.1 启动时间&#xff08;内部时钟可不改&#xff09;2.2 主频2.2.1 系统时钟配置2.2.2 108MHz宏定义第一处第二处第三处第四处第五处 2.2.3 串口2.2.4 FLASH 四、总结 一…

c语言错误总结

函数 A:void类型函数可以 B&#xff1a;不需要&#xff0c;如果return 不返回任何值&#xff0c;函数会在return语句执行后终止执行&#xff0c;后面的语句不会执行 C&#xff1a;对的 D&#xff1a;不可能&#xff0c;return只能返回一个数据 A:函数不一定有返回值 B:可以…

php伪协议 [NISACTF 2022]easyssrf

打开题目 我们直接用 file:/// 协议读取看看flag文件 file:///flag 点击curl得到回响 得到提示告诉我们应该看看提示文件 file:///fl4g 跟着去访问了一下 再跟着去访问 从代码中我们可以看出 get传参file&#xff0c;我们用stristr检测file参数里面是否含有file&#xff…

企业需要哪些数字化管理系统?

企业需要哪些数字化管理系统&#xff1f; ✅企业引进管理系统肯定是为了帮助整合和管理大量的数据&#xff0c;从而优化业务流程&#xff0c;提高工作效率和生产力。 ❌但是&#xff0c;如果各个系统之间不互通、无法互相关联数据的话&#xff0c;反而会增加工作量和时间成本…