Linux下JNI調用簡單實例操作全過程
開發環境:Linux(Ubuntu 11.04) + JDK 7實例說明:利用JNI調用本地代碼的方法來實現一個計算Int數組總和的功能
使用JNI調用本地代碼,整個開發流程主要包括以下幾個步驟:
1、創建一個Java類(IntArray.java);
2、使用javac編譯該類(生成IntArray.class);
3、使用javah -jni 產生頭文件(生成IntArray.h);
4、使用本地代碼實現頭文件中定義的方法(編寫IntArray.c);
5、編譯生成本地動態庫(生成libIntArray.so);
6、使用Java運行程序。
一、創建一個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"); } }注:
1、在Java代碼中聲明本地方法必須有"native"標識符,native修飾的方法,在Java代碼中隻作為聲明存在。例如: private native int sumArray(int[] arr);
2、在調用本地方法前,必須首先裝載含有該方法的本地庫. 如IntArray.java中所示,置於static塊中,在Java VM初始化一個類時,首先執行這部分代碼,這可保證調用本地方法前,裝載了本地庫。
static{ System.loadLibrary("IntArray"); }
二、使用javac編譯該類(生成IntArray.class)
javac IntArray.java
三、使用javah -jni 產生頭文件(生成IntArray.h)
javah -jni IntArray
生成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
四、使用本地代碼實現頭文件中定義的方法(編寫IntArray.c)
複製IntArray.h成IntArray.c,對於IntArray.c做以下修改:
1、添加頭文件:#include "IntArray.h"
2、去掉以下幾句
#ifndef _Included_IntArray
#define _Included_IntArray
#endif
3、實現頭文件中定義的方法
IntArray.c具體代碼如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class IntArray */ #include "IntArray.h" #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
五、編譯生成本地動態庫(生成libIntArray.so)
根據本地代碼(IntArray.h,IntArray.c)生成本地動態庫,命令如下:
gcc -I/usr/lib/jvm/java-7-sun/include/ -I/usr/lib/jvm/java-7-sun/include/linux/ -fPIC -shared -o libIntArray.so IntArray.c注:
其中 -I後麵是java的include文件夾地址,請根據您具體的java版本以及安裝路徑作相應改變;
-f後麵的PIC表示生成的庫中符號是與位置無關的(PIC就是Position Independent Code),關於PIC,可以參考這篇文章
<a href="https://www.gentoo.org/proj/en/hardened/pic-guide.xml">Introduction to Position Independent Code</a>
-shared表示共享,共享庫後綴名.so可以認為是shared object的簡稱;
-o libIntArray.so,可以理解為編譯後輸出libIntArray.so庫。
六、使用Java運行程序
java IntArray
可能出現以下結果:
snowdream@snowdream:~$ 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)
分析異常提示可知,我們之前生成的共享庫不在係統默認的共享庫路徑中,程序找不到共享庫報錯。
解決方法有兩個:
1、臨時指定共享庫libIntArray.so的路徑。
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH注:該方法隻在當前會話窗口有效,切換到另外一個終端窗口,則需要重新指定共享庫路徑。
2、運行時加上參數指定共享庫libIntArray.so的路徑。
java -Djava.library.path=. IntArray注:-D:設置Java平台的係統屬性。 此時JavaVM可以在當前位置找到該庫。
通過以上任意方法,您都可以得到正確的運行結果:
snowdream@snowdream:~$ java IntArray Sum = 45
最後更新:2017-04-02 06:51:52