在linux下進行JNI開發

前期準備:

1、Java JDK

2、gcc

3、g++

注意:gcc和g++的版本號要一致:如下:

[qiaoning@qiaoning ~]$ gcc --version
gcc (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2)
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) 4.6.3 20120306 (Red Hat 4.6.3-2)
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文件:內容如下:

#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
注意:這兒可能產生的錯誤:

1、

gcc: error trying to exec 'cc1plus': execvp: No such file or directory

原因:沒有安裝g++,或者gcc和g++的版本不一致

2、

/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 
此命令生成生成 libhello.so.1.0


接下來將生成的共享庫拷貝爲標準文件名

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 虛擬機崩潰。

參考鏈接:http://www.ibm.com/developerworks/cn/java/l-linux-jni/


發佈了86 篇原創文章 · 獲贊 99 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章