JNI技术之静态注册
一.JNI技术简介
JNI是Java Native Interface的缩写,通过这种机制可以实现JAVA代码调用C/C++写的接口,也可以在C/C++回调JAVA代码。
二.JAVA代码中调用C/C++接口
JAVA只需要加载相应的C/C++的库,就可以在java中调用C/C++的函数了的。
class Test {
//通过"native"修饰成员函数接口,表示这个函数接口是由C/C++来实现的
public native void helloworld();
static {
System.out.println("start load static lib");
//通过System.loadLibrary()加载对应的动态库
System.loadLibrary("HelloWorld");
}
public static void main(String[] args) {
Test mObj = new Test();
mobj.helloworld();
}
}
动态库中一般由多个函数接口,那么java又是怎么知道它想调用的那个接口的呢。
#include <stdio.h>
#include <jni.h>
#include "Test.h"
// 这里的JNIEXPORT,JNICALL都是一个空的宏,只取标识作用
// Java 表明这个函数最后要被JAVA调用的
// Test JAVA层的类名
// helloworld JAVA层的成员函数名
JNIEXPORT void JNICALL Java_Test_helloworld(JNIEnv *env, jobject obj) {
printf("hello world\n");
return;
}
实际上,当java加载完动态库后,在它调用helloworld()方法时,它就在函数库中找Java_Test_helloworld这个函数,如果存在,则调用它,如果不存在则会报错的,这种技术也叫静态注册。
由于java中存在函数重载现象,所以在C/C++实现相应的接口时,对应的函数名也是有变化的。
其实在java方面已经帮助我们做好了的,在我们把java程序编译后,我们可以通过JDK,用javah命令从.class文件中得到C/C++中实现的函数造型。
javac Test.java
javah -jni 类名
这个时候在本地就会生成一个类名命名的.h头文件。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Test */
#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Test
* Method: helloworld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Test_helloworld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
三.生成动态库,运行JAVA程序
1.生成动态库
gcc -fpic -shared -o libhelloworld.so hello.c -I /usr/lib/jvm/java-8-openjdk-amd64/include/ -I /usr/lib/jvm/java-8-openjdk-amd64/include/linux/
其中-I 指定jni.h文件所在的路径
2.运行Java程序
刚运行时可能出现找不到动态库
此时有两种方式添加动态库路径
2.1 export LD_LIBRARY_PATH=.
2.2 java -Djava.library.path=. Test