|
@@ -0,0 +1,151 @@
|
|
|
|
|
+# Java的JNI入门HelloWorld
|
|
|
|
|
+
|
|
|
|
|
+> JNI(Java Native Interface)是从开始Java1.0提供的一种在JVM中调用本地方法的机制
|
|
|
|
|
+>
|
|
|
|
|
+> 本地方法是指C/C++的函数
|
|
|
|
|
+
|
|
|
|
|
+### Java代码
|
|
|
|
|
+
|
|
|
|
|
+使用`native`关键字定义本地本地方法
|
|
|
|
|
+
|
|
|
|
|
+使用System.load()或者System.loadLibrary()方法加载本地方法的动态链接库
|
|
|
|
|
+
|
|
|
|
|
+- load()方法用于加载指定的动态链接库,参数为动态链接库全路径
|
|
|
|
|
+- loadLibrary()方法用于加载特定目录(比如系统的默认存储动态链接库的目录)下的动态链接库,参数为动态链接库的名称
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+package space.anyi.jni.helloWorld;
|
|
|
|
|
+
|
|
|
|
|
+public class Main {
|
|
|
|
|
+ static {
|
|
|
|
|
+ //加载动态连接库
|
|
|
|
|
+ //load用于加载指定的动态链接库,参数为动态链接库全路径
|
|
|
|
|
+ System.load("/home/yangyi/JNI-learn/c/helloWorld/JNI_Hello_World.so");
|
|
|
|
|
+ //loadLibrary用于加载特定目录(比如系统的默认存储动态链接库的目录)下的动态链接库,参数为动态链接库的名称
|
|
|
|
|
+ //可以在启动JVM时添加参数-Djava.library.path参与指定加载动态链接库的目录
|
|
|
|
|
+// System.loadLibrary("JNI_Hello_World.so");
|
|
|
|
|
+ }
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ //调用本地方法
|
|
|
|
|
+ staticHelloWorld();
|
|
|
|
|
+ new Main().instanceHelloWorld();
|
|
|
|
|
+ }
|
|
|
|
|
+ //定义一个静态的本地方法
|
|
|
|
|
+ public static native void staticHelloWorld();
|
|
|
|
|
+ //定义一个普通的本地方法
|
|
|
|
|
+ public native void instanceHelloWorld();
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 编译Java代码生成JNI需要的头文件
|
|
|
|
|
+
|
|
|
|
|
+使用`javac -h ${workDir}/c/helloWorld/ ${workDir}/space/anyi/jni/helloWorld/Main.java`命令编译并生成对应定义本地方法的头文件
|
|
|
|
|
+
|
|
|
|
|
+得到名为"**space_anyi_jni_helloWorld_Main.h**"对应的头文件
|
|
|
|
|
+
|
|
|
|
|
+> 头文件的命名规则为:`包名_类名.h`
|
|
|
|
|
+>
|
|
|
|
|
+> 包名中分割符点"**.**"使用下划线"**_**"替代
|
|
|
|
|
+
|
|
|
|
|
+头文件中本地方法的命名规则为:`Java_包名_类名_方法名`
|
|
|
|
|
+
|
|
|
|
|
+> 完整的方法签名为:`JNIEXPORT 方法返回类型 JNICALL Java_包名_类名_方法名`
|
|
|
|
|
+>
|
|
|
|
|
+> 本地方法有两个固定的参数
|
|
|
|
|
+>
|
|
|
|
|
+> 1. 第一个参数
|
|
|
|
|
+> - JNIEnv*:环境变量的指针
|
|
|
|
|
+> 2. 第二个参数
|
|
|
|
|
+> - jclass:jclass为class对象对应的结构体
|
|
|
|
|
+> - jobject:jobject为实例对象对应的结构体
|
|
|
|
|
+>
|
|
|
|
|
+> - 当本地方为静态方法时,第二个参数为jclass
|
|
|
|
|
+> - 当本地方法为实例普通方法时,第二个参数为jobject
|
|
|
|
|
+
|
|
|
|
|
+头文件中使用了"**jni.h**"头文件,该头文件由JDK提供,在JDK的"**include**"目录中,后续编译时需要使用
|
|
|
|
|
+
|
|
|
|
|
+```c
|
|
|
|
|
+/* DO NOT EDIT THIS FILE - it is machine generated */
|
|
|
|
|
+#include <jni.h>
|
|
|
|
|
+/* Header for class space_anyi_jni_helloWorld_Main */
|
|
|
|
|
+
|
|
|
|
|
+#ifndef _Included_space_anyi_jni_helloWorld_Main
|
|
|
|
|
+#define _Included_space_anyi_jni_helloWorld_Main
|
|
|
|
|
+#ifdef __cplusplus
|
|
|
|
|
+extern "C" {
|
|
|
|
|
+#endif
|
|
|
|
|
+/*
|
|
|
|
|
+ * Class: space_anyi_jni_helloWorld_Main
|
|
|
|
|
+ * Method: staticHelloWorld
|
|
|
|
|
+ * Signature: ()V
|
|
|
|
|
+ */
|
|
|
|
|
+JNIEXPORT void JNICALL Java_space_anyi_jni_helloWorld_Main_staticHelloWorld
|
|
|
|
|
+ (JNIEnv *, jclass);
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Class: space_anyi_jni_helloWorld_Main
|
|
|
|
|
+ * Method: instanceHelloWorld
|
|
|
|
|
+ * Signature: ()V
|
|
|
|
|
+ */
|
|
|
|
|
+JNIEXPORT void JNICALL Java_space_anyi_jni_helloWorld_Main_instanceHelloWorld
|
|
|
|
|
+ (JNIEnv *, jobject);
|
|
|
|
|
+
|
|
|
|
|
+#ifdef __cplusplus
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+#endif
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+### 实现本地方法
|
|
|
|
|
+
|
|
|
|
|
+导入头文件"space_anyi_jni_helloWorld_Main.h"
|
|
|
|
|
+
|
|
|
|
|
+并实现头文件中定义的函数
|
|
|
|
|
+
|
|
|
|
|
+```c
|
|
|
|
|
+//导入头文件
|
|
|
|
|
+#include "space_anyi_jni_helloWorld_Main.h"
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
+//实现静态本地方法
|
|
|
|
|
+JNIEXPORT void JNICALL Java_space_anyi_jni_helloWorld_Main_staticHelloWorld(JNIEnv *, jclass){
|
|
|
|
|
+ printf("static Hello World!\n");
|
|
|
|
|
+}
|
|
|
|
|
+//实现实例普通本地方法
|
|
|
|
|
+JNIEXPORT void JNICALL Java_space_anyi_jni_helloWorld_Main_instanceHelloWorld(JNIEnv *, jobject){
|
|
|
|
|
+ printf("instance Hello World!\n");
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+### 编译本地方法的代码
|
|
|
|
|
+
|
|
|
|
|
+编译C代码
|
|
|
|
|
+
|
|
|
|
|
+`gcc -c -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -o c/helloWorld/JNI_Hello_World.o c/helloWorld/JNI_Hello_World.c`
|
|
|
|
|
+
|
|
|
|
|
+> 在目录"c/helloWorld"下产生编译结果"JNI_Hello_World.o"
|
|
|
|
|
+
|
|
|
|
|
+将编译产物编译为动态链接库
|
|
|
|
|
+
|
|
|
|
|
+`gcc -shared -fPIC -o c/helloWorld/JNI_Hello_World.so c/helloWorld/JNI_Hello_World.o -lc`
|
|
|
|
|
+
|
|
|
|
|
+> 在目录"c/helloWorld"下产生编译结果"JNI_Hello_World.so"
|
|
|
|
|
+
|
|
|
|
|
+### 运行测试
|
|
|
|
|
+
|
|
|
|
|
+`java -cp src/main/java/ space.anyi.jni.helloWorld.Main`
|
|
|
|
|
+
|
|
|
|
|
+>输出结果
|
|
|
|
|
+>
|
|
|
|
|
+>```bash
|
|
|
|
|
+>yangyi@debain12:~/JNI-learn$ java -cp src/main/java/ space.anyi.jni.helloWorld.Main
|
|
|
|
|
+>static Hello World!
|
|
|
|
|
+>instance Hello World!
|
|
|
|
|
+>```
|
|
|
|
|
+
|
|
|
|
|
+### 参考资料
|
|
|
|
|
+
|
|
|
|
|
+[JNI 使用笔记](https://icejoywoo.github.io/2022/08/22/intro-to-jni.html)
|