JNI是什么?
JNI是Java Native Interface的缩写,通过使用 Java 本地接口书写程序,允许Java代码和其他语言写的代码进行交互。
怎样使用?
1、声明 native 方法或属性,native方法或者属性对应的就是预留给 C 语言实现的接口。
public class JNIUtils {
static{
try{
//装载动态链接库文件
System.loadLibrary("GetMiNISeedRecord");
}catch(UnsatisfiedLinkError e){
System.err.println("Native code library failed to load." + e);
System.exit(1);
}
}
public native MiNiseed getMiNiSeedRecord(String inputFile);
}
public class MiNiseed {
private String startTime;
private ArrayList<String> simples;
.....
}
2、编译声明的 Java 文件。
javac -d . MiNiseed.java
javac -d . JNIUtils.java
javah readminiseed.JNIUtils
注:①javac命令:因为在源码中使用了package的命令,所以编译的时候需要用"-d ."参数,其中"."表示在当前目录生成与上一级文件夹同名的文件夹来存放编译生成 .class文件。其次,如果声明的方法是泛型方法,如本例子所示,则指定的方法实体类同样需要编译。②javah命令:类文件名前面加上包名,生成 readminiseed_JNIUtils.h 的文件(包名_类型.h 的文件)。
3、C语言来实现函数 Java 里定义的 native 方法,和 readminiseed_JNIUtils.h文件中的接口名称保持一致。
在该包下新建一个 C 语言源文件,该文件就是接口的具体实现方法,文件的名称就是后面生成并加载的动态链接库的名称。打开上一步生成的头文件,复制头文件里预留的接口方法。
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "readminiseed_JNIUtils.h"
JNIEXPORT jobject JNICALL Java_readminiseed_JNIUtils_getMiNiSeedRecord(JNIEnv *env, jobject object, jstring string){
/**
* 1. (*env)->FindClass得到类
* 2. (*env)->AllocObject新建一个类的示例
* 3. (*env)->GetFieldID得到域ID
* 4. 设置域
*
*
**/
//获得需要传递的指定类
jclass jcRec = (*env)->FindClass(env, "readminiseed/MiNiseed");
//获取类型签名
jfieldID jftime = (*env)->GetFieldID(env, jcRec, "startTime","Ljava/lang/String;");
jfieldID jfsimples = (*env)->GetFieldID(env, jcRec, "simples", "Ljava/util/ArrayList;");
// 新建一个MiNiseed对象
jobject joRec = (*env)->AllocObject(env, jcRec);
//对time属性赋值
jstring jstrn = (*env)->NewStringUTF(env, "2013-01-01T12:23:34.235");
(*env)->SetObjectField(env, joRec, jftime, jstrn);
//初始化arraylist
jclass list_cls = (*env)->FindClass(env,"Ljava/util/ArrayList;");
//取得java的arraylist 初始化方法
jmethodID arraylist_init=(*env)->GetMethodID(env,list_cls, "<init>","()V");
//取得 add 方法
jmethodID arraylist_add= (*env)->GetMethodID(env,list_cls,"add","(Ljava/lang/Object;)Z");
//新建arraylist对象
jobject obj_arraylist =(*env)->NewObject(env,list_cls, arraylist_init, "");
for(int i = 0 ; i < 3 ; i++)
{
jstring str = (*env)->NewStringUTF(env,"Native");
//执行Arraylist类实例的add方法,添加一个属性
(*env)->CallBooleanMethod(env,obj_arraylist,arraylist_add, str);
}
//将对象中的arraylist类型的属性赋值
(*env)->SetObjectField(env, joRec, jfsimples, obj_arraylist);
return joRec;
}
4、编译,生成动态库文件。
gcc -fPIC -D_REENTRANT -I/home/ubuntu/services/java/jdk8/include -I/home/ubuntu/services/java/jdk8/include/linux -c GetMiNISeedRecord.c
注:-I 后面接的是java安装目录中 jni.h 文件所在目录、以及 jni_md.h 所在目录。
gcc -shared GetMiNISeedRecord.o -o libGetMiNISeedRecord.so
注:.so 文件命名规范:遵循 lib + 文件名 + 扩展名的原则,否则,加载动态链接库的时候找不到文件。
5、使用生成的动态库文件。(在第一步中已经完成,写在静态方法中,只要初始化该类就会首先加载库)
System.loadLibrary("GetMiNISeedRecord");
注:库的名称就是 .so文件的名称(去掉lib)或者 C 语言源文件的名称。
6、直接运行可能会报错 java.lang.UnsatisfiedLinkError,需要在 idea 中设置 run->Edit Configurations-> VM Options 添加一行内容。
-Djava.library.path=".so文件的路径"