使用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