JNI(Java Native Interface)是从开始Java1.0提供的一种在JVM中调用本地方法的机制
本地方法是指C/C++的函数
使用native关键字定义本地本地方法
使用System.load()或者System.loadLibrary()方法加载本地方法的动态链接库
loadLibrary()方法用于加载特定目录(比如系统的默认存储动态链接库的目录)下的动态链接库,参数为动态链接库的名称
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();
}
使用javac -h ${workDir}/c/helloWorld/ ${workDir}/space/anyi/jni/helloWorld/Main.java命令编译并生成对应定义本地方法的头文件
得到名为"space_anyi_jni_helloWorld_Main.h"对应的头文件
头文件的命名规则为:
包名_类名.h包名中分割符点"."使用下划线"_"替代
头文件中本地方法的命名规则为:Java_包名_类名_方法名
完整的方法签名为:
JNIEXPORT 方法返回类型 JNICALL Java_包名_类名_方法名本地方法有两个固定的参数
- 第一个参数
- JNIEnv*:环境变量的指针
- 第二个参数
- jclass:jclass为class对象对应的结构体
- jobject:jobject为实例对象对应的结构体
- 当本地方为静态方法时,第二个参数为jclass
- 当本地方法为实例普通方法时,第二个参数为jobject
头文件中使用了"jni.h"头文件,该头文件由JDK提供,在JDK的"include"目录中,后续编译时需要使用
/* 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"
并实现头文件中定义的函数
//导入头文件
#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
输出结果
yangyi@debain12:~/JNI-learn$ java -cp src/main/java/ space.anyi.jni.helloWorld.Main static Hello World! instance Hello World!