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

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

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

相关文章

【Unity】入门

文章目录 概述常用组件各类文件基础知识创建工程工程目录介绍五个窗口面板创建代码和场景 脚本与编程鼠标的输入键盘的输入代码来操作组件获取物体API资源的使用API定时调用与线程向量的基本运算预制体与实例 物理系统与组件案例实操作快捷键来源 Unity已广泛运用到各个领域&am…

如何在Windows上搭建WebDAV服务并通过内网穿透实现公网访问

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav,并且结合cpolar的内网穿透工具实现在公网访…

结构型模式 | 适配器模式

一、适配器模式 1、原理 适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式主要分为三类:类适配器模式、对象适配器模式、接口…

【ARM Cortex-M 系列 5 -- RT-Thread renesas/ra4m2-eco 移植编译篇】

文章目录 RT-Thread 移植编译篇编译os.environ 使用示例os.putenv使用示例python from 后指定路径 编译问题_POSIX_C_SOURCE 介绍编译结果 RT-Thread 移植编译篇 本文以瑞萨的ra4m2-eco 为例介绍如何下载rt-thread 及编译的设置。 RT-Thread 代码下载: git clone …

T2I-Adapter: 让马良之神笔(扩散模型)从文本生成图像更加可控

文章信息 单位:北大深张健团队,腾讯ARC lab 源码: https://github.com/TencentARC/T2I-Adapter 图1. 插个DXL的渲染图,这么真实的光感,感觉PS都可以被取代了 目录 文章信息前言一、介绍二、相关工作1.图像合成与转换2 扩散模型3 适…

Deployment Controller详解(下)

上一篇在《Deployment Controller详解(上)》中介绍了Deployment Controller 的创建、更新和回滚。了解了这三个功能,基本上也就懂得了大厂PaaS平台中服务的灰度升级、失败回滚等操作是如何实现的了。 接下来本文会介绍Deployment Controller…

引领汽车营销新趋势,3DCAT实时云渲染助力汽车三维可视化

当前,汽车产业发展正从电动化的上半场,向智能化的下半场迈进。除了车机技术体验的智能化之外,观车体验的智能化也不容忽视。 这是因为,随着数字化、智能化、个性化的趋势,消费者对汽车的需求和期待也越来越高&#xf…

CSS overflow-anchor

overflow-anchor 为了认识这个属性, 我们需要先看一种常见的现象. 即在网页加载中, 图片常常比文字加载更慢, 这样图片加载完成后可能会将文字向下顶. 比如下图演示 <div class"overflow"><img id"bg" src"" height"150" al…

【NI-RIO入门】使用其他文本语言开发CompactRIO

1.FPGA 接口Python API Getting Started — FPGA Interface Python API 19.0.0 documentation 2.FPGA接口C API FPGA 接口 C API 是用于 NI 可重配置 I/O (RIO) 硬件&#xff08;例如 NI CompactRIO、NI Single-Board RIO、NI 以太网 RIO、NI FlexRIO、NI R 系列多功能 RIO 和…

STM32的以太网外设+PHY(LAN8720)使用详解(7):以太网数据接收及发送测试

0 工具准备 1.野火 stm32f407霸天虎开发板 2.LAN8720数据手册 3.STM32F4xx中文参考手册 4.Wireshark1 以太网数据接收测试 1.1 以太网数据接收测试&#xff08;轮询&#xff09; 我们在主循环内轮询RX DMA描述符标志位查看是否接收到了数据&#xff0c;如果接收到了则将数据…

校园助手示例安卓、ios基于Flutter,小程序基于mpvue,前端基于VueJS,后端Flask(附源码)

warning master分支正在经历大量的重写&#xff0c;请至v4分支查看可运行的版本。 <div align"center"> <img src"logo.png" width "200" height "200" alt"SHUhelper" aligncenter /> <h3>SHUh…

网络通信--深入理解网络和TCP / IP协议

计算机网络体系结构 TCP/IP协议族 TCP / IP 网络传输中的数据术语 网络通信中的地址和端口 window端查看IP地址和MAC地址&#xff1a;ipconfig -all MAC层地址是在数据链路层的&#xff1b;IP工作在网络层的 MAC是48个字节&#xff0c;IP是32个字节 在子网&#xff08;局域…

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

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 SCP&#xff08;Secure Copy&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;的文件传输协议&#xff0c;它可以在本地和远程主机之间安全地复制文件。在Ubuntu系统下&#xff0c;我们可以使用scp命令来实现这个功…

java-sec-code中rmi

java-sec-code中rmi 暂时没有搞懂原理&#xff0c;这里只说明利用方法 java-sec-code 作者给出的是使用ysoserial进行利用 测试环境搭建 docker环境下&#xff0c;1099端口默认不开启&#xff0c;这里使用idea运行org.joychou.RMI.Server即可 个人电脑java环境分为1.8.381 1.8.…

Spring核心源码解析

Spring 框架核心源码 1、使用 Spring 框架 2、反射机制 IoC 控制反转 Inverse of Control 创建对象的权限&#xff0c;Java 程序中需要用到的对象不再由程序员自己创建&#xff0c;而是交给 IoC 容器来创建。 IoC 核心思想 1、pom.xml <dependencies><!-- 引入 …

pytorch张量的创建

张量的创建 张量&#xff08;Tensors&#xff09;类似于NumPy的ndarrays &#xff0c;但张量可以在GPU上进行计算。从本质上来说&#xff0c;PyTorch是一个处理张量的库。一个张量是一个数字、向量、矩阵或任何n维数组。 import torch import numpy torch.manual_seed(7) # 固…

机器学习-数学学习汇总

***I数学只是一个工具&#xff0c;会使用&#xff0c;能解决问题就可以了&#xff0c;精确例如到3.14够用就可以了*** 微积分作用&#xff1a;解决非线性问题 学习&#xff1a;27分。 高中数学&#xff1a; 1.高中数学所有知识点表格总结&#xff0c;高中知识点一个不漏&am…

RLHF对LLM泛化性和多样性的影响

paper&#xff1a;Understanding the effects of RLHF on LLM generalisation and diversity 0 背景知识 标准的RLHF finetuning pipeline一般包含3个阶段&#xff1a; supervised fine-tuning (SFT)。对预训练的模型进行用language modeling的方式进行微调。reward modelin…

【湖仓一体尝试】MYSQL和HIVE数据联合查询

爬了两天大大小小的一堆坑&#xff0c;今天把一个简单的单机环境的流程走通了&#xff0c;记录一笔。 先来个完工环境照&#xff1a; mysqlhadoophiveflinkicebergtrino 得益于IBM OPENJ9的优化&#xff0c;完全启动后的内存占用&#xff1a; 1&#xff09;执行联合查询后的…

AI时代Python量化交易实战:ChatGPT引领新时代

文章目录 《AI时代Python量化交易实战&#xff1a;ChatGPT让量化交易插上翅膀》关键点内容简介作者简介购买链接 《AI时代架构师修炼之道&#xff1a;ChatGPT让架构师插上翅膀》关键点内容简介作者简介 赠书活动 《AI时代Python量化交易实战&#xff1a;ChatGPT让量化交易插上翅…