导读

我们知道通过Java通过JNI可以调用C/C++代码,C/C++也可以通过JNI调用java代码,那么JNI是怎么将Java方法与Native的方法对应起来的呢?

JVM查找Native方法有两种方式:
1、按照JNI规范的命名规则进行查找,这种方式叫静态注册。
2、调用JNI提供的RegisterNatives函数,将本地函数注册到JVM中,这种方式叫动态注册。

静态注册

所谓静态注册就是按照JNI规范书写函数名:

java_类路径_方法名(路径用下划线分隔)

当我们使用Android Studio新建一个Native工程时默认生成的JNI函数就是静态注册的,例如下面就是一个静态注册的简单例子:

extern "C" JNIEXPORT jstring JNICALL
Java_com_fly_jnitest_MainActivity_stringFromJNI(JNIEnv* env,jobject obj) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}

静态注册的方式是系统的默认方式,使用简单,但是灵活性比较差,如果修改了Java中的Native函数所在类的包名或类名,则需要同时修改C/C++函数名称(头文件、源文件等)。

属性描述符与函数描述符

在了解动态注册之前,我们先来了解JNI中的属性描述符和函数签名的概念。

JNI属性描述符也就是变量类型在JNI中的表示方式,它是由属性的声明类型决定的。例如使用"I"表示int属性,使用"F"表示float属性,使用"D"表示double属性,使用"Z"表示boolean属性等。

对于引用各类型属性的描述符,比如java.lang.String,需要以字母"L"开头, 解析来是JNI类描述符并使用一个分号结束,Java中完整类名中的".“被”/"替换掉了。因此,对于java.lang.String类型需要使用以下形式的属性描述符:
Ljava/lang/String;

数组类型的描述符由"["以及数组元素类型的描述符组成,例如,[I表示整型数组的属性描述符,以此类推。

我们可以使用javap工具从class文件生成属性描述符。

与属性描述符类似,函数也有函数描述符,通常我们又称为函数签名,一个函数描述符由他的参数类型和返回值类型组成,参数类型在前,且使用一对括号括起来,参数类型是以他们在函数声明中的顺序罗列的,多个参数类型之间是没有分隔符,如果一个方法没有参数,使用一对空的括号表示即可。函数的返回值类型紧跟在包裹参数类型的右括号后边。

例如(I)V代指接收一个整型参数且返回值为空的函数。()D代指的是没有输入参数,返回值是一个double类型的函数。

注意:不要被C函数中像"int f(void)“这样的函数原型误导,误认为”(V)I"是它的方法描述符,其实"()I"才函数f的函数描述符。

动态注册

在库加载时会自动调用JNI_OnLoad()函数,开发者经常会JNI_OnLoad()函数做一些初始化操作,动态注册就是在这里进行的。调用API是env->RegisterNatives(clazz, gMethods, numMethods)

env->RegisterNatives(clazz, gMethods, numMethods)是一个接受三个参数的函数,第一个参数是Java对应的类,第二个参数是JNINativeMethod数组,第三个参数是JNINativeMethod数组的长度,也就是需要注册的方法的个数。
其中JNINativeMethod表示的是方法方法的映射关系,它包括Java中的方法名,对应的方法签名和Native映射的函数方法三个信息。

相比静态注册,动态注册的灵活性更高,如果修改了java native函数所在类的包名或类名,仅调整Java native函数的签名信息即可。

以下展示了一个动态注册的例子:

// 前两个参数还是固定的
jstring stringFromJNI(JNIEnv *jniEnv,jobject jobj){return jniEnv->NewStringUTF("hello from C++ string");
}static const JNINativeMethod nativeMethod[] = {// Java中的函数名{"stringFromJNI",// 函数签名信息"()Ljava/lang/String;",// native的函数指针(void *) (stringFromJNI)},
};// 类库加载时自动调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reversed)
{JNIEnv *env = NULL;// 初始化JNIEnvif(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){return JNI_FALSE;}// 找到需要动态动态注册的Jni类jclass jniClass = env->FindClass("com/fly/jnitest/MainActivity");if(nullptr == jniClass){return JNI_FALSE;}// 动态注册env->RegisterNatives(jniClass,nativeMethod,sizeof(JNINativeMethod)/sizeof(nativeMethod));// 返回JNI使用的版本return JNI_VERSION_1_6;
}

相比于静态注册,动态注册不必在每次运行调用Native方法都去进行方法查找,所以相对来说动态注册的性能更高一些。

推荐阅读

JNI基础简介
JNI之数组与字符串的使用

关注我,一起进步,人生不止coding!!!

JNI静态注册与动态注册相关推荐

  1. NDK 开发之 JNI 方法静态注册与动态注册

    1 前言 上文说到,进行 NDK 开发的时候,我们首先需要把 Java 方法声明为 native,然后编写对应的 C/C++ 代码,并编译成为动态链接库,在调用 Java 方法前加载动态链接库即可调用 ...

  2. 你应该了解的JNI知识(一)——静态注册与动态注册

    最近一直在做native这边的跨平台开发,整个结构基本就是下图: 大体说来就是,底层C/C++代码.那么对于两端分别有不同的处理: 对于Android端而言,由于需要给Java端使用,因此需要提供JN ...

  3. java 动态加载jni_JNI静态注册与动态注册详解

    JNI注册,是指将java层方法(native关键字修饰的)和C层方法对应起来,以实现java层代码调用c层代码的目的.JNI注册分为静态注册和动态注册两种,静态注册是通过固定格式方法名进行关联,动态 ...

  4. android的动态注册,Android应用开发之BroadcastReceiver(广播)的静态注册和动态注册 --Android开发...

    本文将带你了解Android应用开发之BroadcastReceiver(广播)的静态注册和动态注册 --Android开发,希望本文对大家学Android有所帮助 BroadcastReceiver ...

  5. Oracle监听的静态注册和动态注册

    静态注册:通过解析listene.ora文件 动态注册:由PMON进程动态注册至监听中 在没有listener.ora配置文件的情况下,如果启动监听,则监听为动态注册.用图形化netca创建的监听,默 ...

  6. Oracle listener静态注册和动态注册(zt)

    曾经遇到一个问题,oracle10g里通过netca命令得到的listener.ora默认就是动态监听,但是默认没有设置instance_name和service_names参数.我一般是先启动db, ...

  7. 【我的C语言学习进阶之旅】介绍一下NDK开发中关于JNI函数的两种注册方式:静态注册和动态注册

    目录 一.要介绍本篇博客的原因 二.静态注册 2.1 实现原理 2.2 实现过程 2.3 弊端 2.4 示例 三.动态注册 3.1 实现原理 3.2 实现过程 3.3 优点 3.4 示例 一.要介绍本 ...

  8. Android复习12【广播接收者-BroadcastReceiver(简单案例-发送广播、静态注册、动态注册、本地广播、代码示例(别处登陆踢用户下线)、常用系统广播总结、音乐播放器)】

    2020-04-28[11周-周二] 音乐播放器Android代码下载:https://wws.lanzous.com/ifqzihaxvij 目   录 简单案例-发送广播 2)动态注册实例(监听网 ...

  9. lsnrctl status区分静态注册与动态注册

    unknow:静态注册 ready或blocked:动态注册 a.如果先启动监听,后启动数据库 Service "PLSExtProc" has 1 instance(s).   ...

最新文章

  1. robotframework接口测试(二)—post request
  2. mina处理断包和粘包
  3. oracle vm virtualbox如何设置u盘启动_电脑自主U盘装机 如何设置U盘启动
  4. iOS进阶之底层原理-weak实现原理
  5. 当前最好的非深度迁移学习方法:流形空间下的分布对齐
  6. 在html页面中加入矢量图,HTML页面插入SVG的多种方式
  7. 前端学习(3087):vue+element今日头条管理-关于接口的使用
  8. 我张哥做的这ARM开发板,真酸爽!
  9. simpledateformat格式_为什么日期格式化时必须有使用y表示年,而不能用Y?
  10. mysql 主从 日志_mysql主从复制基于日志复制
  11. 自定义类加载器与热部署
  12. Quartz 定时任务 cron 表达式详解
  13. 微信小程序生成海报功能
  14. C语言atoi和atol函数详解和示例
  15. luogu P4315 月下“毛景树”
  16. 小程序转uniapp——disabled
  17. SAP固定资产中一些概念:折旧码,折旧范围和折旧表
  18. 计算机研究生论文怎怎么写,计算机硕士研究生论文大纲格式 计算机硕士研究生论文大纲怎样写...
  19. 函数模板和类模板详解
  20. win10x64 批处理自动安装打印机

热门文章

  1. mysql设置字符集 php_MySQL字符集编码设置与PHP显示乱码的解决办法
  2. 马克思为何拒绝极限论?
  3. 第七章 从POP3服务器提取电子邮件
  4. Metrics,入门到应用
  5. google也有贴吧了
  6. 16012009徐小东_考核二
  7. python数据分析与挖掘实战(航空公司客户价值分析)
  8. Vue.js从入门到精通(全),爆肝十一万字,“建议收藏”,国庆福利!!!
  9. VMware Aria Automation 8.10 - 现代基础架构自动化平台
  10. r语言descstats_R语言学习笔记之聚类分析