# 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 /* 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 //实现静态本地方法 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)