Android JNI浅析、Java和Native通信对象的传值和回调
简单了解一下jni
JNI是一个本地编程接口,它允许运行在Java虚拟机的Java代码与用其他语言(如C,C++和汇编)编写的库交互。
jni函数签名
首先看一下java类型对应的jni类型:
| Java类型 | 符号 |
|---|---|
| Boolean | Z |
| Byte | B |
| Char | C |
| Short | S |
| Int | I |
| Long | J |
| Float | F |
| Double | D |
| Void | V |
| 数组 | [ 比如:int[] -> [I ,如果是二维数组 int[][] -> [[I |
| objects | 以"L"开头,以";"结尾,中间是用"/" 隔开的包及类名。比如:Ljava/lang/String;如果是嵌套类,则用$来表示嵌套。 |
比如:
privite native int test(String arg);
则它的签名为:
(Ljava/lang/String;)I
函数参数的传递
- 基本类型(如整型,字符等)在Java和native之间是采用值传递
- Java对象采用的是引用传递
关于局部引用的相关内容,可以参考之前的文章:
JNI内存方面说明以及相关类型手动释放内存
JavaVM和JNIEnv
这两个结构体在jni.h中有定义:
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
这里也能看出c版本和c++版本,在使用调用上有一些不同,c++相当于又包了一层!
下边看一下c++的版本:
JavaVM
struct _JavaVM {const struct JNIInvokeInterface* functions;#if defined(__cplusplus)jint DestroyJavaVM(){ return functions->DestroyJavaVM(this); }jint AttachCurrentThread(JNIEnv** p_env, void* thr_args){ return functions->AttachCurrentThread(this, p_env, thr_args); }jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); }jint GetEnv(void** env, jint version){ return functions->GetEnv(this, env, version); }jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args){ return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
#endif /*__cplusplus*/
};
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); }......
}
总的来说:
JavaVM:是java虚拟机环境,每个进程有且只有只有一个。
JNIEnv: 是线程上下文环境,每个线程只有一个,不能跨线程。
我们可以通过JNIEnv来获取一个JavaVM:
jint GetJavaVM(JNIEnv *env, JavaVM **vm);// vm:用来存放获得的虚拟机的指针的指针。
// return:成功返回0,失败返回其他。
也可以通过JavaVM来获取一个JNIEnv:
jint GetEnv(void** env, jint version)
上边也提到了JNIEnv是线程绑定的,所以通常,用全局的JavaVM获取一个当前线程的JNIEnv的时候,通常需要绑定到当前线程:
char thread_name[128] = { 0 };
prctl(PR_GET_NAME, (char *)(thread_name));
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = thread_name;
args.group = NULL;
gJvm->AttachCurrentThread(&pEnv, (void *)(&args))
同样的,也需要在不使用的时候解绑:
gJvm->DetachCurrentThread();
本地函数的静态加载和动态加载
所谓静态加载,就是我们常见的,jni函数的声明是Java_包名_类名_方法名(参数...)这样子的,Java方法和本地函数之间的映射关系编译器已经帮我们做了。
下边了解一下动态加载:
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);
JNI_OnLoad方法是在动态库被加载时调用,而JNI_OnUnload则是在本地库被卸载时调用。所以这两个函数就是一个本地库最重要的两个生命周期方法。
在JNI_OnLoad()中,就可以手动注册本地函数,做好对java方法的映射。
一般的可以这个样子:
const JNINativeMethod gMethods[] = {{"native函数名", "native函数签名", (void *)native函数}, //第三个为函数指针...//别的native函数
};JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){JNIEnv *env = NULL;jint result = -1;if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {return result;}// 动态注册native functionjclass clazz = env->FindClass("com.xx.xx.xxclass"); env->RegisterNatives(clazz, &method, 1) //第三个参数为总的数量// 返回jni的版本return JNI_VERSION_1_6;
}
访问字段和函数
对于jni函数中传入的jobject对象,要想访问对象的字段和函数,就需要先获取对应的class引用!
jobject testObject; //假设我们已经有了这么一个对象jclass testCls = env->GetObjectClass(testObject); //获取class引用
//int testFiled;
//int test(String arg);
jfieldID testFiledId = env->GetFieldID(testCls, "testFiledID", "I");
jmethodID testMethodId = env->GetMethodID(testCls, "test", "(Ljava/lang/String;)I");// 注意对字段的get/set,函数的调用,都必须使用具体的jobject对象,而不能是class引用
env->GetIntField(testObjcet, testFiledId);
env->CallIntMethod(testObject, testMethodId, "arg...");
java像Native中的对象的传递,一般也是安装上边的方式来进行,取出字段的值,再赋值给native对应的对象!
如果是native的对象回调到java层怎么做?
// 先找到class引用
jclass jcs = env->FindClass("com/xx/xx/xxclass");
// 创建对象有两种方法
// 第一种是调用类的构造函数:mthodId就是构造函数的id
jmethodID cls_constructor = env->GetMethodID(jcs, "<init>", "()V");jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);// 第二种是直接alloc对象
jobject AllocObject(jclass clazz)//然后将native对象赋值给jobject即可!
相关文章:
Android JNI浅析、Java和Native通信对象的传值和回调
简单了解一下jni JNI是一个本地编程接口,它允许运行在Java虚拟机的Java代码与用其他语言(如C,C和汇编)编写的库交互。 jni函数签名 首先看一下java类型对应的jni类型: Java类型符号BooleanZByteBCharCShortSIntILongJFloatFDo…...
linux目录/usr/lib/systemd/system目录详解
文章目录前言一. systemd介绍二. service 脚本详解2.1 [Unit] 区块2.2 [Service] 区块2.3 [Install] 区块总结前言 init的进化经历了这么几个阶段: CentOS 5: SysV init,串行 CentOS 6:Upstart,并行,借鉴ubuntu CentOS 7:Syste…...
408考研计算机之计算机组成与设计——知识点及其做题经验篇目4:CPU的功能和基本结构
随着考研的慢慢复习,我们逐渐进入了计算机组成与设计的第五章中央处理器。它原名为CPU。姓C,名PU,字中央处理器,号计组难点,乃计算机之中心与核心部件,小编称之曰能算能控,赐名曰九天宏教普济生…...
2022-12-10青少年软件编程(C语言)等级考试试卷(五级)解析
2022-12-10青少年软件编程(C语言)等级考试试卷(五级)解析T1、漫漫回国路 2020年5月,国际航班机票难求。一位在美国华盛顿的中国留学生,因为一些原因必须在本周内回到北京。现在已知各个机场之间的航班情况,求问他回不回得来(不考虑转机次数和机票价格)。 时间限制:10…...
刷题专练之链表(一)
文章目录前言一、 移除链表元素1.题目介绍2.思路3.代码二、反转链表1.题目介绍2.思路3.代码三、链表的中间结点1.题目介绍2.思路3.代码四、链表的中间结点1.题目介绍2.思路3.代码前言 以下是链表经常考的面试题,我在这里进行归纳和讲解,采取的是循序渐进…...
elasticsearch高级查询api
yml配置 #es配置 spring:elasticsearch:rest:uris: 192.168.16.188:9200添加依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>使用编程的形式…...
力扣-股票的资本损益
大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:1393. 股票的资本损益二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他…...
蓝桥杯刷题冲刺 | 倒计时26天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.路径2.特别数的和3.MP3储存4.求和1.路径 题目 链接: 路径 - 蓝桥云课 (lanqiao.cn…...
嵌入式软件开发之Linux 用户权限管理
目录 Ubuntu 用户系统 权限管理 权限管理命令 权限修改命令 chmod 文件归属者修改命令 chown Ubuntu 用户系统 Ubuntu 是一个多用户系统,我们可以给不同的使用者创建不同的用户账号,每个用户使用各自的账号登陆,使用用户账号的目的一是方便…...
2023-03-15 RabbitMQ
RabbitMQ整合 官网erlang版本 : 20.3.8.x 官方rabbitMq版本: rabbitmq-server-generic-unix-3.7.14.tar.xz 1.安装 1.1 安装erlang 1.安装环境 yum -y install make gcc gcc-c kernel-devel m4 ncurses-devel openssl-devel2.在/usr/local/下创建erlangapp文件…...
二叉树链式结构的实现
文章目录1.二叉树的遍历1.1前序、中序以及后序遍历1.2代码测试1.3层序遍历1.4二叉树遍历习题2.节点个数以及高度2.1二叉树节点个数2.2叶子节点个树2.3第k层节点个数2.4树的高度1.二叉树的遍历 1.1前序、中序以及后序遍历 学习二叉树结构,最简单的方式就是遍历。所…...
蓝桥杯刷题冲刺 | 倒计时28天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.卡片2.数字三角形3.购物单4.回文日期1.卡片 题目 链接: 卡片 - 蓝桥云课 (lanqiao…...
一文带你吃透操作系统
文章目录1. 进程、线程管理2. 内存管理3. 进程调度算法4. 磁盘调度算法5. 页面置换算法6. 网络系统7. 锁8. 操作系统知识点文章字数大约1.9万字,阅读大概需要65分钟,建议收藏后慢慢阅读!!!1. 进程、线程管理 进程和线程…...
计算机网络英文简称汇总
分类名词全拼汉译概述B2CBusiness-to-Consumer商对客概述P2PPeer-to-Peer对等概述C/SClient-Server服务器-客户机概述ITUInternational Telecommunication Union国际电信联盟概述IEEEInstitute of Electrical and Electronics Engineers电气与电子工程师协会概述ICCCInternatio…...
腾讯云云服务器标准型S5性能配置简单测评
腾讯云服务器标准型S5实例CPU采用Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,主频2.5GHz,睿频3.1GHz,标准型S5云服务器基于全新优化虚拟化平台,配有全新的Intel Advanced Vector Extension (AVX-512) 指令集&#…...
RK3568平台开发系列讲解(Linux系统篇)消息队列
🚀返回专栏总目录 文章目录 一、创建消息队列二、发送和接收消息三、内核结构沉淀、分享、成长,让自己和他人都能有所收获!😄 📢消息队列在如下两个方面上比管道有所增强: 消息队列中的数据是有边界的,发送端和接收端能以消息为单位进行交流,而不再是无分隔的字节流…...
2021电赛国一智能送药小车(F题)设计报告
2021电赛国一智能送药小车(F题)设计报告 【写在前面的话】 电赛是一个很奇妙的过程,可能有些人觉得电赛的门槛太高,那便意味着,当你决定要参加电赛的那一刻起,这一段路、这些日子就注定不会太轻松…...
刚工作3天就被裁了....
前言 还有谁?刚上三天班就被公司公司的工作不适合我,叫我先提升一下。 后面我也向公司那边讨要了一个说法,我只能说他们那边的说辞让我有些不服气。 现在之所以把这件事上记录一下,一是记录一下自己的成长轨迹,二是…...
docker安装elasticsearch与head教程完整版—.NET Core Web Api与elasticsearch打造全站全文搜索引擎
默认已经有docker环境 下载与安装 elasticsearch ,从hub.docker里面可以看到最新版本的镜像,选择你想要的版本 本教程是以 7.17.7 为案例,为啥不适用最新的,首先个人一般需用最新的版本,如果有亢很难填,其次…...
蓝桥冲刺31天之315
没有一个冬天不可逾越 也没有一个春天不会来临 所有美好的食物,都会有一个等待的过程 低谷时蛰伏,静默时沉淀 做三四月的事,在八九月自有答案 目录 A:0的个数 题目描述: 输入格式 输出格式 样例输入 样例输出 评测用例规模与…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
