前期準備:
1、Java JDK
2、gcc
3、g++
注意:gcc和g++的版本號碼要一致:如下:
[juan@juan~]$ gcc --version gcc (GCC) <span style="color: #ff0000;" > 4.6 . 3 20120306 (Red Hat 4.6 . 3 - 2 )</span> Copyright (C) 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. [qiaoning@qiaoning ~]$ g++ --version bash: g++: command not found... [qiaoning@qiaoning ~]$ gcc --version gcc (GCC) <span style="color: #ff0000;" > 4.6 . 3 20120306 (Red Hat 4.6 . 3 - 2 )</span> Copyright (C) 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
linux(Fedora) 安裝gcc yum install gcc 安裝g++ yum install gcc-c++
確保上述準備工作完成後開始下邊的工作:
Java代碼:
public class Hello { static { try { System.loadLibrary("hello" ); } catch (UnsatisfiedLinkError e) { e.printStackTrace(); } } public Hello() {}; public native void SayHello(String strName); }
在終端輸入 javac Hello.java 後產生Hello.class 檔案
然後:javah Hello 產生 Hello.h檔案
然後在相同的目錄下建立一個Hello.cpp檔案:內容如下:
Cpp代碼
#include "Hello.h" #include <stdio.h> // 與 Hello.h 中函式宣告相同 JNIEXPORT void JNICALL Java_Hello_SayHello (JNIEnv * env, jobject arg, jstring instring) { // 從 instring 字串取得指向字串 UTF 編碼的指標 const jbyte *str = (const jbyte *)env->GetStringUTFChars( instring, JNI_FALSE ); printf("Hello,%s\n" ,str); // 通知虛擬機器本地代碼不再需要通過 str 訪問 Java 字串。 env->ReleaseStringUTFChars( instring, (const char *)str ); return ; }
接下來編譯產生共用庫:
gcc -I/usr/lib/jvm/java- 1.6 . 0 -openjdk- 1.6 . 0.0 /include -I/usr/lib/jvm/java- 1.6 . 0 -openjdk- 1.6 . 0.0 /include/linux -fPIC -c Hello.cpp
注意:這兒可能產生的錯誤:
gcc: error trying to exec 'cc1plus' : execvp: No such file or directory
原因:沒有安裝g++,或者gcc和g++的版本不一致
/usr/lib/jvm/java- 1.6 . 0 -openjdk- 1.6 . 0.0 根據自己機器實際的目錄做相應的調整
編譯成功後產生Hello.o
gcc -shared -Wl,-soname,libhello.so. 1 -o libhello.so. 1.0 Hello.o
gcc -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 Hello.o
此命令產生產生 libhello.so.1.0
接下來將產生的共用庫拷貝為標準檔案名稱
cp libhello.so. 1.0 libhello.so
最後通知動態連結程式此共用檔案的路徑。
export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
接下來將產生的共用庫拷貝為標準檔案名稱
cp libhello.so.1.0 libhello.so
最後通知動態連結程式此共用檔案的路徑。
export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
最後是java測試代碼:
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。
應用中注意事項:
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 虛擬機器崩潰。