转载请注明出处:http://blog.csdn.net/xyang81/article/details/41854185

通过第一篇文章,大家明白了调用native方法之前,首先要调用System.loadLibrary接口加载一个实现了native方法的动态库才能正常访问,否则就会抛出java.lang.UnsatisfiedLinkError异常,找不到XX方法的提示。现在我们想想,在Java中调用某个native方法时,JVM是通过什么方式,能正确的找到动态库中C/C++实现的那个native函数呢?

JVM查找native方法有两种方式:

1> 按照JNI规范的命名规则

2> 调用JNI提供的RegisterNatives函数,将本地函数注册到JVM中。(后面会详细介绍)

本文通过第一篇文章HelloWorld示例中的Java_com_study_jnilearn_HelloWorld_sayHello函数来详细介绍第一种方式:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_study_jnilearn_HelloWorld */#ifndef _Included_com_study_jnilearn_HelloWorld
#define _Included_com_study_jnilearn_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_study_jnilearn_HelloWorld* Method:    sayHello* Signature: (Ljava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello(JNIEnv *, jclass, jstring);#ifdef __cplusplus
}
#endif
#endif

JNIEXPORT 和 JNICALL的作用:

在上篇文章中,我们在将HelloWorld.c编译成动态库的时候,用-I参数包含了JDK安装目录下的两个头文件目录:

gcc -dynamiclib -o /Users/yangxin/Library/Java/Extensions/libHelloWorld.jnilib jni/HelloWorld.c -framework JavaVM -I/$JAVA_HOME/include -I/$JAVA_HOME/include/darwin

其中第一个目录为jni.h头文件所在目录,第二个是跨平台头文件目录(mac os x系统下的目录名为darwin,在windows下目录名为win32,linux下目录名为linux),用于定义与平台相关的宏,其中用于标识函数用途的两个宏 JNIEXPORT 和 JNICALL,就定义在darwin目录下的jni_md.h 头文件中。在Windows中编译dll动态库规定,如果动态库中的函数要被外部调用,需要在函数声明中添加 __declspec(dllexport)标识,表示将该函数导出在外部可以调用。在Linux/Unix系统中,这两个宏可以省略不加。这两个平台的区别是由于各自的编译器所产生的可执行文件格式不一样。这里有篇文章详细介绍了两个平台编译的动态库区别:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html。JNICALL在windows中的值为__stdcall,用于约束函数入栈顺序和堆栈清理的规则。

Windows下jni_md.h头文件内容:

#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_#define JNIEXPORT __declspec(dllexport)
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcalltypedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;#endif 

Linux下jni_md.h头文件内容:

#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_#define JNIEXPORT
#define JNIIMPORT
#define JNICALLtypedef int jint;
#ifdef _LP64 /* 64-bit Solaris */
typedef long jlong;
#else
typedef long long jlong;
#endiftypedef signed char jbyte;#endif

从Linux下的jni_md.h头文件可以看出来,JNIEXPORT 和 JNICALL是一个空定义,所以在Linux下JNI函数声明可以省略这两个宏。

函数的命名规则:

用javah工具生成函数原型的头文件,函数命名规则为:Java_类全路径_方法名。如Java_com_study_jnilearn_HelloWorld_sayHello,其中Java_是函数的前缀,com_study_jnilearn_HelloWorld是类名,sayHello是方法名,它们之间用 _(下划线) 连接。

函数参数:

JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello(JNIEnv *, jclass, jstring);

第一个参数:JNIEnv* 是定义任意native函数的第一个参数(包括调用JNI的RegisterNatives函数注册的函数),指向JVM函数表的指针,函数表中的每一个入口指向一个JNI函数,每个函数用于访问JVM中特定的数据结构。

第二个参数:调用java中native方法的实例或Class对象,如果这个native方法是实例方法,则该参数是jobject,如果是静态方法,则是jclass

第三个参数:Java对应JNI中的数据类型,Java中String类型对应JNI的jstring类型。(后面会详细介绍JAVA与JNI数据类型的映射关系)

函数返回值类型:

夹在JNIEXPORT和JNICALL宏中间的jstring,表示函数的返回值类型,对应Java的String类型

总结:

当我们熟悉了JNI的native函数命名规则之后,就可以不用通过javah命令去生成相应java native方法的函数原型了,只需要按照函数命名规则编写相应的函数原型和实现即可。

比如com.study.jni.Utils类中还有一个计算加法的native实例方法add,有两个int参数和一个int返回值:public native int add(int num1, int num2),对应JNI的函数原型就是:JNIEXPORT jint JNICALL Java_com_study_jni_Utils_add(JNIEnv *, jobject, jint,jint);

JNI/NDK开发指南(二)——JVM查找java native方法的规则相关推荐

  1. JNI/NDK开发指南(八)——调用构造方法和父类实例方法

    转载请注明出处:http://blog.csdn.net/xyang81/article/details/44002089 在第6章我们学习到了在Native层如何调用Java静态方法和实例方法,其中 ...

  2. JNI/NDK开发指南(三)——JNI数据类型及与Java数据类型的映射关系

    2019独角兽企业重金招聘Python工程师标准>>> 转载请注明出处:http://blog.csdn.net/xyang81/article/details/42047899 当 ...

  3. JNI/NDK开发指南(十一)——JNI异常处理

    转载请注明出处:http://blog.csdn.net/xyang81/article/details/45770551 异常简介 异常,显而意见就是程序在运行期间没有按照正常的程序逻辑执行,在执行 ...

  4. JNI/NDK入门指南之jobject和jclass

          JNI/NDK入门指南之jobject和jclass Android JNI/NDK入门指南目录 JNI/NDK入门指南之正确姿势了解JNI和NDK JNI/NDK入门指南之JavaVM和 ...

  5. JNI查找 native 方法的规则(静态、动态注册)

    转载自:JNI查找 native 方法的规则 通过上一篇文章,大家明白了调用 native 方法之前,首先要调用 System.loadLibrary 接口加载一个实现了native 方法的动态库才能 ...

  6. Java本地方法/Java native方法/JNI

    一.什么是JNI? JNI是 Java Native Interface的缩写,又叫Java本地方法/Java native方法.用于Java代码和其他语言写的代码进行交互.使用java与本地已编译的 ...

  7. ndk开发(二)JNI、java互调

    目录 1.新建java类,首先静态加载库 2.java调用JNI的方法 3.JNI调用java 上集说到开发环境的搭建,本集踏出第一步,与java互调 1.新建java类,首先静态加载库 static ...

  8. jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .

    在上一章中我们学习到了如何在本地代码中访问任意Java类中的静态方法和实例方法,本章我们也通过一个示例来学习Java中的实例变量和静态变量,在本地代码中如何来访问和修改.静态变量也称为类变量(属性), ...

  9. Android学Jni/Ndk 开发记录(一)

    治疗拖延症的唯一办法就是:一想起些什么 / 要做些什么就 TM 立马去做! 是的,突然想起我不会 JNI.NDK 开发.解决办法:立马去学! 一:配置 NDK 环境 下载 NDK 写入到配置文件 二: ...

最新文章

  1. html在页面上div绝对定位,html – 中心浮动div在绝对定位div内
  2. 一种广泛存在于Facebook、谷歌、小米、阿里等公司的研发组织管理方式
  3. .svn文件夹_新建SVN仓库并上传项目
  4. 威廉与玛丽学院读计算机博士,威廉与玛丽学院计算机科学(计算运算研究)理学硕士研究生申请要求及申请材料要求清单...
  5. 认识Web前端、Web后端、桌面app和移动app新开发模式 - 基于Node.js环境和VS Code工具...
  6. AGC005D ~K Perm Counting
  7. 掌握这些大数据知识,面试官再也不会怕了!
  8. PyTorch之torch.nn.CrossEntropyLoss()
  9. sdram 时钟相位_Nios II 和SDRAM时钟相位计算
  10. 【转】session和cookie详解
  11. oracle 导出01455,使用exp命令导出报EXP-00008 和ORA-01455的解决方法
  12. 关于JavaScript DOM 编程艺术这本书
  13. ExtJS视频教程 ExtJS入门到精通教程下载
  14. 计算机毕业论文选题影视方向,毕业设计选题方向
  15. 安科瑞DDS/DTS/DTZ系列计量表,具有体积小巧、精度高、可靠性好、安装方便等优点
  16. android下载文件地址,安卓迅雷下载的文件在哪里迅雷下载文件存放位置-独木成林...
  17. 春风拂过希壤,能否成为元宇宙创作的起点?
  18. 恋词题源报刊Unit2
  19. SQL数据库查询LIMIT 数据分页
  20. [第九届蓝桥杯省赛C++B组]明码

热门文章

  1. java 解析rmc_GPS 0183协议GGA、GLL、GSA、GSV、RMC、VTG解释 + 数据解析 | 技术部落
  2. 判断一个字符是西文字符还是中文字符
  3. mysql查询计算机_mysql 查询条件
  4. mac安装win10_在SSD里安装「Windows to go」
  5. 为 HTC 的 Android 手机正名
  6. 架火炬市场现状及未来发展趋势分析
  7. 【电子电路技术】PoE供电技术的优缺点
  8. 三星又来黑iPhone/ 骗的就是90后/ 马斯克让斯坦福摊上事儿了… 今日更多新鲜事在此...
  9. iOS15 WebSocket断连问题
  10. ios逆向越狱手机必备工具篇