소스 검색

doc:JNI的入门文档

yangyi 1 주 전
부모
커밋
c25344e5f7
1개의 변경된 파일151개의 추가작업 그리고 0개의 파일을 삭제
  1. 151 0
      doc/Java的JNI入门HelloWorld.md

+ 151 - 0
doc/Java的JNI入门HelloWorld.md

@@ -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)