导读

我们知道通过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. 呼叫中心的服务水平管理
  2. 13成都邀请赛 1005 Naive and Silly Muggles
  3. onvif规范的实现:成功实现ONVIF协议RTSP-Video-Stream与OnvifDeviceManager的视频对接
  4. Ansible自动化运维基础-------ploybook
  5. USACO 保护花朵 Protecting the Flowers, 2007 Jan
  6. 对于我的博客的相关说明
  7. MongoDB学习笔记(二)使用Java操作MongoDB
  8. TensorFlow学习笔记(二十八)CNN的9大模型之AlexNet
  9. 九、PyQt5 QLineEdit输入的子网字符串校验QRegExp
  10. gdb 命令_gdb实用的调试技巧:启动方式、堆栈信息、单步调试
  11. Docker简单入门
  12. js数组(列表)的基本操作
  13. 图卷积网络的半监督学习脉络
  14. VAD(Voice Activity Detection)算法详解
  15. linux扫描后门工具,Linux下rootkit后门检测工具chkrootkit安装使用教程
  16. 关于pdf转html的个人方法,pdf转html的另类方法
  17. python爬取图虫网图库
  18. 室外宽温1口千兆光纤收发器工业导轨式发送机接收机单模单纤单电口
  19. LM317稳压电源设计
  20. 查看漏洞库平台有哪些?

热门文章

  1. 缺这项能力,做不了技术管理工作
  2. Linux MySQL下载安装
  3. PE 123(数论)
  4. Dijkstra算法原理及代码实现
  5. 块状链表(STL rope)
  6. 医院计算机网络故障护士,医院信息系统护士工作站运行中的管理 【护理相关讨论版】...
  7. 微信提现失败:openid与商户appid不匹配;更换了openid,但商户单号未更新
  8. 传研发人员被「祭天」,继小红书「崩」上热搜后,网友:“这难道不是测试的锅?”...
  9. Skycc营销软件,给她美好的每一天
  10. Maven实战与原理分析(一):maven超全使用指南总结