1 首先建立一個簡單的java類:
public class Hello
{
static
{
try
{
//此處即為本地方法所在連結庫名
System.loadLibrary("hello");
}
catch(UnsatisfiedLinkError e)
{
System.err.println( "Cannot load hello library:\n " +
e.toString() );
}
}
public Hello()
{
}
//聲明的本地方法
public native void SayHello(String strName);
}
這裡有個地方要注意,就是 這個類最好不要加包資訊。因為類在某個包下面,使用javah命令產生*.h標頭檔的時候會不一樣,比如在test包下,就會產生test_Hello.h,而且 在jni調用的時候,也有區別,為了方便起見,我們這裡就不加包了,免得麻煩,:)
然後,編譯得到Hello.class
2 產生 Hello.h
使用命令:javah Hello
這裡有一點要注意,如果這個命令報錯,有可能是因為你沒有當前路徑到設定環境變數classpath中,所以:
javah -classpath"." Hello.class
這樣寫就OK了, 後面也許還會碰到類似的環境變數問題。
3 在與Hello.h相同的路徑下建立一個CPP檔案Hello.cpp。內容如下:
#include "Hello.h"JNIEXPORT void JNICALL Java_Hello_SayHello (JNIEnv * env, jobject arg, jstring instring){ const char *str = env->GetStringUTFChars( instring, JNI_FALSE ); printf("Hello,%s\n",str); env->ReleaseStringUTFChars( instring, str ); return;}
這個Hello.cpp 的代碼,跟IBM的例子略有不同,詳細原因 大家自己去查查jni.h
4.編譯產生共用庫
a. 編譯命令,產生Hello.o
g++ -I /usr/lib/jvm/java-6-sun-1.6.0.03/include -I /usr/lib/jvm/java-6-sun-1.6.0.03/include/linux -fPIC -c Hello.cpp
b.產生動態庫檔案,libhello.so.1.0
g++ -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 Hello.o
這裡的2個命令也跟IBM文章的例子有所不同。因為使用gcc編譯得到動態庫,在jni調用的時候,某些情況會有異常,所以這裡改用g++。
接下來將產生的共用庫拷貝為標準檔案名稱
cp libhello.so.1.0 libhello.so
最後通知動態連結程式此共用檔案的路徑。
export LD_LIBRARY_PATH='pwd':$LD_LIBRARY_PATH
這裡用export 加入共用檔案的路徑,有時候會有點問題,比如:環境變數不會馬上更新等等。
還有一個辦法,就是直接將libhello.so拷貝到 /usr/lib 或者/lib 等系統庫目錄下
5.編寫一個簡單的Java程式來測試我們的本地方法。
將如下源碼存為ToSay.java:
import Hello;import java.util.*;public class ToSay{public static void main(String argv[]){ToSay say = new ToSay();}public ToSay(){Hello h = new Hello();//調用本地方法向John問好h.SayHello("John");}}用javac編譯ToSay.java,產生ToSay.class 向執行普通Java程式一樣使用java ToSay,我們會看到在螢幕上出現Hello,John。 6 以下是IBM的文章中的建議: 應用中注意事項 1. 如果可以通過TCP/IP實現Java代碼與本地C/C++代碼的互動工作,那麼最好不使用以上提到的JNI的方式,因為一次JNI調用非常耗時,大概要花0.5~1個毫秒。 2. 在一個Applet應用中,不要使用JNI。因為在 applet 中可能引發安全異常。 3. 將所有本地方法都封裝在單個類中,這個類調用單個 DLL。對於每種目標作業系統,都可以用特定於適當平台的版本替換這個 DLL。這樣就可以將本地代碼的影響減至最小,並有助於將以後所需的移植問題包含在內。 4. 本地方法要簡單。盡量將產生的DLL 對任何第三方運行時 DLL 的依賴減到最小。使本地方法盡量獨立,以將載入DLL 和應用程式所需的開銷減到最小。如果必須要運行時 DLL,則應隨應用程式一起提供它們。 5. 本地代碼運行時,沒有有效地防數組越界錯誤、錯誤指標引用帶來的間接錯誤等。所以必須保證保證本地代碼的穩定性,因為,絲毫的錯誤都可能導致Java虛擬機器崩潰。 7 思考的問題 我以前一直在想,如果我使用JNI來調用C/C++實現的socket通訊庫,會不會比java自己的nio效能要好? 貌似IBM的兄弟的回答是否定的。 也有人不同意這個意見,說因為Java代碼與本地C/C++代碼的互動工作不是那麼頻繁,即使浪費0.5~1個毫秒,也沒什麼關係。 貌似BEA的weblogic(weblogic 9以後的版本)就採用這個做法。 以後有機會我就來做個實驗,測試一下,呵呵。 當然,有兄弟已經測試過了,來告訴我,就最好啦,哈哈!!!
|