JNI 静态注册和动态注册
一、前言
当执行一个 Java 的 native 方法时,虚拟机是怎么知道该调用 so 中的哪个方法呢?这就需要用到注册的概念了,通过注册,将指定的 native 方法和 so 中对应的方法绑定起来(函数映射表),这样就能够找到相应的方法了。
注册分为 静态注册 和 动态注册 两种。默认的实现方式即静态注册。
二、静态注册
1. 定义
通过 JNIEXPORT 和 JNICALL 两个宏定义声明,在虚拟机加载 so 时发现上面两个宏定义的函数时就会链接到对应的 native 方法。
2. 对应规则
Java + 包名 + 类名 + 方法名
其中使用下划线将每部分隔开,包名也使用下划线隔开,如果名称中本来就包含下划线,将使用下划线加数字替换。
示例(包名:com.afei.jnidemo,类名:MainActivity):
// Java native method
public native String stringFromJNI();
// JNI method
JNIEXPORT jstring JNICALL
Java_com_afei_jnidemo_MainActivity_stringFromJNI( JNIEnv *env, jobject instance);// Java native method
public native String stringFrom_JNI();
// JNI method
JNIEXPORT jstring JNICALL
Java_com_afei_jnidemo_MainActivity_stringFrom_1JNI(JNIEnv *env, jobject instance);
3. 优点
- 简单明了
4. 缺点
- 必须遵循注册规则
- 名字过长
- 运行时去找效率不高
三、动态注册
1. 定义
通过 RegisterNatives 方法手动完成 native 方法和 so 中的方法的绑定,这样虚拟机就可以通过这个函数映射表直接找到相应的方法了。
2. 注册过程示例
a. 假设有两个 native 方法如下:
public native String stringFromJNI(); public static native int add(int a, int b);
b. 通常我们在 JNI_OnLoad 方法中完成动态注册,native-lib.cpp 如下:
#include <jni.h>
#include <string>
#include "log.hpp"extern "C" {jstring stringFromJNI(JNIEnv *env, jobject instance) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}jint add(JNIEnv *env, jclass clazz, jint a, jint b) {return a + b;
}jint RegisterNatives(JNIEnv *env) {jclass clazz = env->FindClass("com/afei/jnidemo/MainActivity");if (clazz == NULL) {LOGE("con't find class: com/afei/jnidemo/MainActivity");return JNI_ERR;}JNINativeMethod methods_MainActivity[] = {{"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI},{"add", "(II)I", (void *) add}};// int len = sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]);return env->RegisterNatives(clazz, methods_MainActivity,sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]));
}jint JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env = NULL;if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR;}jint result = RegisterNatives(env);LOGD("RegisterNatives result: %d", result);return JNI_VERSION_1_6;
}}
c. 分析
如上,我们不再使用 JNIEXPORT 和 JNICALL 两个宏定义声明指定的方法,也不用依照固定的命名规则命名方法(不过通常 jni 里的方法名还是保持和 native 方法的方法名一致,见名思义),而是通过了一个 RegisterNatives 方法完成了动态注册。
3. RegisterNatives 方法解析
定义: jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods)
参数:
- clazz:指定的类,即 native 方法所属的类
- methods:方法数组,这里需要了解一下 JNINativeMethod 结构体
- nMethods:方法数组的长度
JNINativeMethod:
typedef struct {const char* name; // native 的方法名const char* signature; // 方法签名,例如 ()Ljava/lang/String;void* fnPtr; // 函数指针
} JNINativeMethod;
返回值:成功则返回 JNI_OK (0),失败则返回一个负值。
其它:
NDK 学习系列:Android NDK 从入门到精通(汇总篇)
JNI 静态注册和动态注册相关推荐
- NDK 开发之 JNI 方法静态注册与动态注册
1 前言 上文说到,进行 NDK 开发的时候,我们首先需要把 Java 方法声明为 native,然后编写对应的 C/C++ 代码,并编译成为动态链接库,在调用 Java 方法前加载动态链接库即可调用 ...
- 你应该了解的JNI知识(一)——静态注册与动态注册
最近一直在做native这边的跨平台开发,整个结构基本就是下图: 大体说来就是,底层C/C++代码.那么对于两端分别有不同的处理: 对于Android端而言,由于需要给Java端使用,因此需要提供JN ...
- JNI静态注册与动态注册
导读 我们知道通过Java通过JNI可以调用C/C++代码,C/C++也可以通过JNI调用java代码,那么JNI是怎么将Java方法与Native的方法对应起来的呢? JVM查找Native方法有两 ...
- java 动态加载jni_JNI静态注册与动态注册详解
JNI注册,是指将java层方法(native关键字修饰的)和C层方法对应起来,以实现java层代码调用c层代码的目的.JNI注册分为静态注册和动态注册两种,静态注册是通过固定格式方法名进行关联,动态 ...
- android的动态注册,Android应用开发之BroadcastReceiver(广播)的静态注册和动态注册 --Android开发...
本文将带你了解Android应用开发之BroadcastReceiver(广播)的静态注册和动态注册 --Android开发,希望本文对大家学Android有所帮助 BroadcastReceiver ...
- Oracle监听的静态注册和动态注册
静态注册:通过解析listene.ora文件 动态注册:由PMON进程动态注册至监听中 在没有listener.ora配置文件的情况下,如果启动监听,则监听为动态注册.用图形化netca创建的监听,默 ...
- Oracle listener静态注册和动态注册(zt)
曾经遇到一个问题,oracle10g里通过netca命令得到的listener.ora默认就是动态监听,但是默认没有设置instance_name和service_names参数.我一般是先启动db, ...
- 【我的C语言学习进阶之旅】介绍一下NDK开发中关于JNI函数的两种注册方式:静态注册和动态注册
目录 一.要介绍本篇博客的原因 二.静态注册 2.1 实现原理 2.2 实现过程 2.3 弊端 2.4 示例 三.动态注册 3.1 实现原理 3.2 实现过程 3.3 优点 3.4 示例 一.要介绍本 ...
- Android复习12【广播接收者-BroadcastReceiver(简单案例-发送广播、静态注册、动态注册、本地广播、代码示例(别处登陆踢用户下线)、常用系统广播总结、音乐播放器)】
2020-04-28[11周-周二] 音乐播放器Android代码下载:https://wws.lanzous.com/ifqzihaxvij 目 录 简单案例-发送广播 2)动态注册实例(监听网 ...
- lsnrctl status区分静态注册与动态注册
unknow:静态注册 ready或blocked:动态注册 a.如果先启动监听,后启动数据库 Service "PLSExtProc" has 1 instance(s). ...
最新文章
- Python内置函数(58)——input
- SAP实施要重视用户体验
- 下一个嵌入式大神,难道不是你吗?
- java学习(25):三目运算符
- 二级java编写用户界面例题,单选题11—20:2012年计算机二级VB用户界面设计练习题及答案-计算机二级-233网校...
- Python之网络爬虫(selenium爬取动态网页、爬虫案例分析、哈希算法与RSA加密)
- 个人博客网站建设_利用Github+Jeklly搭建个人博客网站
- 借贷宝java_【人人行(借贷宝)Java面试】借贷宝java后端开发面经。-看准网
- Microsemi Libero使用技巧3——使用FlashPro单独下载程序
- keil4for51与keil4forARM的安装与兼容
- layui数据表格实现内容筛选的全选和反选功能
- 基于JSON+JQuery实现的多条件筛选功能(类似京东和淘宝功能)
- 秒解UTF-8带来的烦恼
- GitHub Desktop图文教程
- 测试用例及其注意事项
- Resources的使用方式
- gdpr通用数据保护条例_从信息安全角度看通用数据保护条例(GDPR)
- mapbox加载天地图
- 一键新机IGRIMACE手机在线源安装方式
- 3月9日——3月13日一年级课程表