(譯)Simple JNI on Ubuntu 9.04

人們可以找到很多關於Solaris和Windows中JNI的教程,而且在那些例子中C++出現得也不是那麼頻繁,出於這個原因,我通過兩個例子來說明一下其使用。

對於下面的程序,要求你使用的SunJDK,而不是OpenJDK(在文章後面我會再次提到這點)。

第一個例子是從Java中傳遞一個字符串到native method中,在native method中打印個性化的Helllo World。

public class HelloWorld {
	public native void sayHi(String name);

	static {
		System.loadLibrary("nativehw");
	}

	public static void main(String[] args) {
		HelloWorld h = new HelloWorld();
		h.sayHi("Night Rider");
	}
}

 

在這裏先說明一下,我們打算通過nativehw庫來調用本地方法sayHi。

編譯的我們類:

javac HelloWorld.java 

 

然後生成本地方法的頭文件:

javah -jni HelloWorld

 

接着實現HelloWorld.h聲明的方法:

(注,注意第一行的include。原文中這段代碼不是很完整,爲保持作者原意,故此這裏我也不做相關修改)

#include 
#include "HelloWorld.h"

using namespace std;

JNIEXPORT void JNICALL Java_HelloWorld_sayHi(JNIEnv *env, jobject o, jstring s)
{
	const char *str = env->GetStringUTFChars(s, 0); cout << "Hello " << str << endl;
	env->ReleaseStringUTFChars(s, str); 
}

 

由於在C++中沒有像Java那樣的垃圾收集器,所以我們需要做一些清理工作。(譯者注:這個是作者的建議,在本段代碼中並未體現出來)

 

寫好後保存爲HelloWorld.cpp然後進行編譯:

g++ -shared -I/usr/lib/j2sdk1.6-sun/include -I/usr/lib/j2sdk1.6-sun/include/linux HelloWorld.cpp -o libnativehw.so 

 

注意不同系統環境的include目錄的路徑可能會有所不同,生成前面提到的nativehw庫。

我們像這樣運行的例子:

java -Djava.library.path=. HelloWorld

 預期的輸出結果是“Hello Night Rider”。

 

 

 

第二個例子將展示用JNI處理一些異常,同樣我們先開始編寫Java代碼:

public class MoreStuff {
	public native double div(double x, double y) throws Exception;

	static {
		System.loadLibrary("whatever");
	}

	public static void main(String[] args) {
		MoreStuff m = new MoreStuff();
		try {
			System.out.println("7.0 / 2.0 = " + m.div(7.0, 2.0));
			System.out.println("0.0 / 0.0 = " + m.div(0.0, 0.0));
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
}

 

 編譯並且生成頭文件:

javac MoreStuff.java
javah -jni MoreStuff

 

實現的聲明的發發的C++代碼如下:

NIEXPORT jdouble JNICALL Java_MoreStuff_div (JNIEnv *env, jobject o, jdouble x, jdouble y)
{
	if(0.0 == y){
		jclass e = env->FindClass("java/lang/IllegalArgumentException");
		if (e == 0) {
			return -3.14;
		}
		env->ThrowNew(e,"Zero argument exception.");
		env->DeleteLocalRef(e);
	}
	return x/y;
}

 

 建議使用更健壯的異常處理機制來處理異常(譯者注:這也是作者的建議,並未在代碼中體現出來)。

 

 

g++ -shared -I/usr/lib/j2sdk1.6-sun/include -I/usr/lib/j2sdk1.6-sun/include/linux MoreStuff.cpp -o libwhatever.so

 

 這裏是執行的操作和輸出的結果:

java -Djava.library.path=.
MoreStuff 7.0 / 2.0 = 3.5
Zero argument exception.

 

爲了讓編譯通過,可能需要編輯JDKHOME/include/jni.h,包括相關文件或目錄(譯者注:此即爲上文中爲何沒有在代碼中包含這個的原因):

#include "jni_md.h"

 或着這樣:

#include "linux/jni_md.h"

 

(譯者:這裏我認爲作者的意思是應該是運行Java例子時使之包括相關的路徑,尤其要注意jni.h和jni.md.h,這兩個頭文件一定不能漏掉。建議在g++中添加-I標誌來特別標明這幾個include路徑)。

這裏是我安裝的JDK路徑的描述,雖然jni.h也是OpenJDK源碼的一部分,但是我卻沒有在Ubuntu8.04的OpenJDK安裝路徑中找到它,所以這也是我強調使用SunJDK的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章