JNI
0x01 What Is JNI
JNI:Java Native Interface
Java是基于C语言实现的,很多底层API都是通过调用JNI来实现的。
与硬件、操作系统交互的操作可以使用JNI来提升程序性能
JNI让Java能够调用编译好的动态链接库里的方法(存在跨平台问题👊)
像我们熟悉的Class.forName()最底层就是C去实现的,它被native修饰

0x02 Best Pratice
定义native修饰方法
javah生成.h头文件
javac -h . JNITest.java(JDK ≥ 10)
老版本:javah -jni JNITest
得到JNITest.h头文件和JNITest.class文件
C++实现头文件
VS新建dll项目,调试属性=》C/C++预编译头 => 不使用预编译头

生成后得到x64的dll
javah生成的头文件中的函数命名方式是有非常强制性的约束
(JNIEnv *, jclass, jstring)表示分别是JNI环境变量对象、java调用的类对象、参数入参类型
无法包含jni.h的看这里:JNI报错:"无法打开源文件jni.h" "JNIEXPORT此声明没有存储类或类型说明符"_"无法打开源文件 “jni.h"
加载dll
将生成的JniHi.dll放在class同目录下,执行java JNITest
成功弹出计算器
Dynamic Register
上面只是定义了一个native方法,然后通过System.loadLibrary()或System.load()加载native方法对应的动态链接库,来实现Java层面调用C/C++提供的服务。
还有另外一种方法来实现native方法,在JNI_OnLoad函数中进行函数映射,将java里面的方法映射到自己实现的C/C++函数,这样就不用通过javah生成头文件了(还有那串又臭又长的函数名)。JNI_OnLoad会在加载动态链接库时首先被调用。
既然这样的话,我们就能将原本java里定义的native方法映射到我们自己实现的方法。
JNI Interface
JNI_OnLoad
第一个参数表示Java虚拟机,第二个参数一般为NULL,返回值为JNI版本。
JNINativeMethod
该结构体定义了C/C++函数与Java方法的映射
name:Java中定义的native方法名
signature:native方法的函数签名
fnPtr:C/C++中native函数指针
注册的时候需要设置一个JNINativeMethod数组,数组中有几个元素,就表示映射到一个类的多少个native方法。
native方法通过JNI函数来访问JVM中的数据结构。
JNIEnv
Java本地接口环境,一般为一个指针,指向native方法的一个函数表
可以从JavaVM获取JNIEnv,第一个参数为JNIEnv的二级指针,第二个参数为JNI版本
JNIEnv提供了一些与Java建立桥梁的方法,如FindClass,根据类名字符串找到对应的jclass
RegisterNatives 注册C/C++函数,映射到Java层的native方法
clazz:要注册方法所在的Java类
methods:Java方法与native方法映射的关系数组
nMethods:映射的方法个数,一般为methods数组元素的个数
此外JNIEnv还有一些用于jxxx的Java数据类型和C数据类型之间转换的方法,这里不展开。
Build
CLion新建项目

CMakeLists.txt👇
library.cpp👇,这里为方便编写,就不管stdHandles标准输入输出错误这些了。
Build得到一个动态链接库


Last updated
Was this helpful?