Java雖然強大,但對於面向底層的一些操作還是略顯不足,此時唯有通過JNI來進行調用本地方法來擴展Java程序的功能。可以將native方法類比爲Java中聲明的接口方法,然後在外部用其他語言進行實現。
其實現步驟如下:
1、在Java中聲明native()方法,然後編譯;
2、用javah產生一個.h文件;
3、寫一個.c或.cpp文件實現native導出方法,其中需要include第二步產生的.h文件,另根據需要可以自己再include其他文件;
4、將第三步的.c或.cpp文件編譯成動態鏈接庫文件(這個不同的系統下操作方法不同);
5、在Java中用System.loadLibrary()方法加載第四步產生的動態鏈接庫文件,這個native()方法就可以在Java中被訪問了。
顯然,如題所說,網絡上關於Windows下JNI的使用多如牛毛,這裏我就只說一下Linux(我用的是Ubuntu10.04)下的JNI調用。
1.先編寫一個Java文件,這裏我保存爲文件名Test.java
public class Test {
//此處定義的便是native方法
native public void doSomeThing();
public static void main (String args[]) {
Test test = new Test();
test.doSomeThing();
}
static{
//這個作何用處下面的步驟會作說明
System.loadLibrary("libtest");
}
}
之後進行編譯(javac)生成Test.class文件
2.通過javah -jni Test,會生成一個Test.h的頭文件,其內容如下
#include <jni.h>
#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_Test_doSomeThing
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
3接着我再編寫一個Test.c文件來進行
#include <stdio.h>
#include "Test.h" //這裏要包含剛纔生成的頭文件
JNIEXPORT void JNICALL Java_Test_doSomeThing(JNIEnv * name, jobject o)
{
printf("HelloWorld");
return;
}
4將Test.c編譯成動態鏈接庫,下面是其命令
gcc -shared -I /usr/lib/jvm/java-6-sun-1.6.0.20/include -I /usr/lib/jvm/java-6-sun-1.6.0.20/include/linux -I /usr/include Test.c -o libtest.so
解釋一下上面的操作,當然我的系統是Ubuntu10.04,不過關於jdk安裝之後的路徑應該大同小異,自己做下適當的調整即可
/usr/lib/jvm/java-6-sun-1.6.0.20/include下包含的jni.h
/usr/lib/jvm/java-6-sun-1.6.0.20/include/linux下包含的是jni-mid.h
-shared 是設置生成share object的標誌
libtest.so即爲我們需要的動態鏈接庫(等同於Windows下的*.dll文件)。
5.可以再看Test.java中 System.loadLibrary("libtest");的作用了,就是讓其加載libtest而已。
順便說明一下,用static聲明的域不需要用try..catch來捕獲異常,否則還是捕獲一下爲好。
OK,現在大功告成,讓我們來運行該程序即可
java -Djava.library.path=. Test
輸出結果就是...還是你自己試下吧
本文參考了http://www.linux.com/community/blogs/simple-jni-on-ubuntu-904.html,同時可參見我翻譯的中文網址http://arescaiser.iteye.com/blog/804636
額,我先是在OpenOffice上完成的,選擇的是微軟雅黑的字體,只是沒想到JavaEye不支持這個,所以造成了格式亂碼,現在已經改過來了,給大家造成不便敬請諒解