使用JNI调用本地代码,整个开发流程主要包括如下几个步骤:
一、建立一个Java类(IntArray.java);
二、使用javac编译该类(生成IntArray.class);
三、使用javah -jni 产生头文件(生成IntArray.h);
四、使用本地代码实现头文件中定义的方法(编写IntArray.c);
五、编译生成本地动态库(生成libIntArray.so);
六、使用Java运行程序。html
建立Java类:IntArray.java
class IntArray { private native int sumArray(int[] arr); public static void main(String[] args) { IntArray p = new IntArray(); int arr[] = new int[10]; for(int i = 0; i < 10; i++) { arr[i] = i; } int sum = p.sumArray(arr); System.out.println("Sum = " + sum); } static { System.loadLibrary("IntArray"); } }
注:
一、在Java代码中声明本地方法必须有"native"标识符,native修饰的方法,在Java代码中只做为声明存在。例如: private native int sumArray(int[] arr);
二、在调用本地方法前,必须首先装载含有该方法的本地库. 如IntArray.java中所示,置于static块中,在Java VM初始化一个类时,首先执行这部分代码,这可保证调用本地方法前,装载了本地库。java
static {
System.loadLibrary("IntArray");
}linux
2、使用javac编译该类(生成IntArray.class)
javac IntArray.java
3、使用javah -jni 产生头文件(生成IntArray.h)
javah -jni IntArraybash
生成的 IntArray.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class IntArray */ #ifndef _Included_IntArray #define _Included_IntArray #ifdef __cplusplus extern "C" { #endif /* * Class: IntArray * Method: sumArray * Signature: ([I)I */ JNIEXPORT jint JNICALL Java_IntArray_sumArray (JNIEnv *, jobject, jintArray); #ifdef __cplusplus } #endif #endif
4、使用本地代码实现头文件中定义的方法(编写IntArray.c)
复制IntArray.h成IntArray.c,对于IntArray.c作如下修改:
一、添加头文件:#include "IntArray.h"
二、去掉如下几句
#ifndef _Included_IntArray
#define _Included_IntArray
#endif
三、实现头文件中定义的方法:oracle
IntArray.c
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #include "IntArray.h" /* Header for class IntArray */ #ifdef __cplusplus extern "C" { #endif /* * Class: IntArray * Method: sumArray * Signature: ([I)I */ JNIEXPORT jint JNICALL Java_IntArray_sumArray (JNIEnv *env, jobject obj, jintArray arr) { jint buf[10] = {0}; jint i = 0, sum = 0; (*env)->GetIntArrayRegion(env, arr, 0, 10, buf); for(i = 0; i < 10; i++) { sum += buf[i]; } return sum; } #ifdef __cplusplus } #endif
5、编译生成本地动态库(生成libIntArray.so)
根据本地代码(IntArray.h,IntArray.c)生成本地动态库,命令以下:ide
gcc -I /home/oracle/jdk1.8.0_05/include -I /home/oracle/jdk1.8.0_05/include/linux/ -fPIC -shared -o libIntArray.so IntArray.c
其中 -I后面是java的include文件夹地址,请根据您具体的java版本以及安装路径做相应改变;
-f后面的PIC表示生成的库中符号是与位置无关的(PIC就是Position Independent Code),关于PIC,能够参考这篇文章
http://www.gentoo.org/proj/en/hardened/pic-guide.xml ui
-shared表示共享,共享库后缀名.so能够认为是shared object的简称;
-o libIntArray.so,能够理解为编译后输出libIntArray.so库。spa
6、使用Java运行程序
java IntArray命令行
可能出现如下结果:code
java IntArray
Exception in thread "main" java.lang.UnsatisfiedLinkError: no IntArray in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860) at java.lang.Runtime.loadLibrary0(Runtime.java:845) at java.lang.System.loadLibrary(System.java:1084) at IntArray.<clinit>(IntArray.java:15)
分析异常提示可知,咱们以前生成的共享库不在系统默认的共享库路径中,程序找不到共享库报错。
解决方法有两个:
一、临时指定共享库libIntArray.so的路径。
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 注:该方法只在当前会话窗口有效,切换到另一个终端窗口,则须要从新指定共享库路径。也可直接在环境变量中加入:LD_LIBRARY_PATH=.:$ORACLE_HOME/lib:/usr/lib64:/usr/lib:/usr/local/lib64:/usr/local/lib 命令行中使用:source ~/.bash_profile 使当前增长的环境变量生效
二、运行时加上参数指定共享库libIntArray.so的路径。
java -Djava.library.path=. IntArray 注:-D:设置Java平台的系统属性。 此时JavaVM能够在当前位置找到该库。
经过以上任意方法,您均可以获得正确的运行结果:
java IntArray
Sum = 45
--------------------------------------------
文章来源于:http://www.2cto.com/os/201108/101048.html