一、前言

当执行一个 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 静态注册和动态注册相关推荐

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

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

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

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

  3. JNI静态注册与动态注册

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. Python内置函数(58)——input
  2. SAP实施要重视用户体验
  3. 下一个嵌入式大神,难道不是你吗?
  4. java学习(25):三目运算符
  5. 二级java编写用户界面例题,单选题11—20:2012年计算机二级VB用户界面设计练习题及答案-计算机二级-233网校...
  6. Python之网络爬虫(selenium爬取动态网页、爬虫案例分析、哈希算法与RSA加密)
  7. 个人博客网站建设_利用Github+Jeklly搭建个人博客网站
  8. 借贷宝java_【人人行(借贷宝)Java面试】借贷宝java后端开发面经。-看准网
  9. Microsemi Libero使用技巧3——使用FlashPro单独下载程序
  10. keil4for51与keil4forARM的安装与兼容
  11. layui数据表格实现内容筛选的全选和反选功能
  12. 基于JSON+JQuery实现的多条件筛选功能(类似京东和淘宝功能)
  13. 秒解UTF-8带来的烦恼
  14. GitHub Desktop图文教程
  15. 测试用例及其注意事项
  16. Resources的使用方式
  17. gdpr通用数据保护条例_从信息安全角度看通用数据保护条例(GDPR)
  18. mapbox加载天地图
  19. 一键新机IGRIMACE手机在线源安装方式
  20. 3月9日——3月13日一年级课程表

热门文章

  1. 征服面试官的50道Redis高频通关面试题
  2. python json模块_python json模块使用详情
  3. 美食杰-菜谱大全(二)
  4. 关于印发《深圳市福田区支持战略性新兴产业和未来产业集群发展若干措施》的通知
  5. 数据结构 常见排序算法 LOWB三人组 冒泡 选择 插入
  6. 计算机视觉最新研究方向,计算机视觉的主要研究的内容是什么?,计算机视觉研究方向...
  7. 计算机软著发明,时健
  8. 文献阅读笔记怎么写?
  9. 一只兔子帮你理解KNN
  10. 雷声大雨点小,廖翔廖翔你真diao