【java&&jni】jni入門篇

來源:互聯網
上載者:User

【序】我是為了android研究需要才開始研究JNI的。閱讀本例文之前希望你按照上一篇【java】Windows7
下環境變數設定已經對環境變數進行正確設定


本文通過一個簡單的例子來示範如何使用JNI。我們寫一個JAVA程式,並用它調用一個C函數來列印“Hello World!”。

這個過程包含下面幾步:

1、 建立一個類(HelloWorld.java)聲明本地方法。

2、 使用javac編譯源檔案HollowWorld.java,產生HelloWorld.class。使用javah –jni來產生C標頭檔(HelloWorld.h),這個標頭檔裡麵包含了本地方法的函數原型。

3、 用C/C++代碼寫函數原型的實現。

4、 把C/C++函數實現編譯成一個本地庫,產生libHelloWorld.so。

5、 使用java命令運行HelloWorld程式,類檔案HelloWorld.class和本地庫(libHelloWorld.so)在運行時被載入。

現在我們按上述步驟一步步的實現:

一、建立HelloWorld.java

<strong>class HelloWorld{    private native void print();    public static void main(String[] args)    {        new HelloWorld().print();    }    static    {        System.loadLibrary("HelloWorld");    }}</strong>

二、產生HelloWorld.class、HelloWorld.h

1. 編譯HelloWorld.java產生HelloWorld.class

CD到HelloWorld.java所在的目錄,在命令列中運行如下命令:

javac HelloWorld.java

在當前檔案夾編譯產生HelloWorld.class。

2.產生HelloWorld.h

在命令列中運行:

javah -jni HelloWorld    //記住是javah  而不是  java

可能會提示如下錯誤:

錯誤:無法訪問HelloWorld

未找到HelloWorld的類檔案

錯誤的原因的是java的classpath沒有包含當前路勁,解決辦法有兩種:
用下面的命令列代替
javah -classpath $PWD -jni HelloWorld     //其中$PWD為當前路徑,在win7下做好寫上絕對路徑
或者:

export CLASSPATH=$CLASSPATH:$PWD; javah -jni HelloWorld   //Linux編譯環境下的命令

這樣就在能在目前的目錄下產生了HelloWorld.h,內容如下:

<strong>/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloWorld */#ifndef _Included_HelloWorld#define _Included_HelloWorld#ifdef __cplusplusextern "C" {#endif/* * Class:     HelloWorld * Method:    print * Signature: ()V */JNIEXPORT void JNICALL Java_HelloWorld_print  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif</strong>

該檔案中包含了一個函數Java_HelloWorld_print的聲明。這裡麵包含兩個參數,非常重要,後面講實現的時候會講到。

三、用C/C++代碼寫函數原型的實現

在目前的目錄下建立HelloWorld.cpp, 內容如下:

<strong>#include <jni.h>#include <stdio.h>#include "HelloWorld.h"JNIEXPORT void JNICALL     Java_HelloWorld_print(JNIEnv *env, jobject obj){    printf("Hello World!\n");}</strong>注意必須要包含jni.h標頭檔,該檔案中定義了JNI用到的各種類型,宏定義等。jni標頭檔存在於你jdk的安裝路徑下,比如我的jdk安裝在 /usr/lib/jvm/java-1.5.0-sun 目錄下, 那麼jni.h就存在於/usr/lib/jvm/java-1.5.0-sun/include目錄下,這個路徑待會會用到。


函數傳回型別
jstring代表的是傳回型別。這裡應該表示的是java的String.

JNIEXPORT  JNICALL代表的是函數被JNI調用
函數名字
函數名字首先是首碼java,然後是要調用該JNI的Java類的路徑,HelloWorld
接著是Java中申明的函數的名字。 print
函數參數
第一個參數永遠應該是JNIEnv* env,
第二個參數jobject thiz是java中的this指標。
第三個參數開始是Java的函數中的參數。

另外需要注意Java_HelloWorld_print的兩個參數,本例比較簡單,不需要用到這兩個參數。但是這兩個參數在JNI中非常重要。env代表java虛擬機器環境,Java傳過來的參數和c有很大的不同,需要調用JVM提供的介面來轉換成C/C++類型的,就是通過調用env方法來完成轉換的。obj代表調用的對象,相當於c++的this。當 c/C++ 函數需要改變調用對象成員變數時,可以通過操作這個對象來完成。

四、 把C/C++函數實現編譯成一個本地庫,產生libHelloWorld.so

在終端執行如下命令產生libHelloWorld.so:

g++ -I/usr/lib/jvm/java-1.5.0-sun/include/linux/ -I/usr/lib/jvm/java-1.5.0-sun/include/ -fPIC -shared -o libHelloWorld.so HelloWorld.cpp

在目前的目錄產生libHelloWorld.so。注意一定需要包含Java的include目錄(請根據自己系統內容設定),因為Helloworld.c中包含了jni.h。

另外一個值得注意的是在HelloWorld.java中我們LoadLibrary方法載入的是“HelloWorld”,可我們產生的Library卻是libHelloWorld。這是Linux的連結規定的,一個庫的必須要是:lib+庫名+.so。連結的時候只需要提供庫名就可以了

五、 使用java命令運行HelloWorld程式  (執行環境為Linux,.so為Linux下動態庫,不要試圖在Windows下運行)

在終端中輸入運行HelloWorld程式:

java HelloWorld
能會出現如下錯誤:

Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld

出現這個錯誤也是因為CLASSPATH環境變數沒有包含目前的目錄,解決方案與上面提到的一樣:

java -classpath $PWD HelloWorld

或者:

export CLASSPATH=$CLASSPATH:$PWD; java HelloWorld

緊接著可能也會出現下面的一個錯誤:

<strong>Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path<br />at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)<br />at java.lang.Runtime.loadLibrary0(Runtime.java:822)<br />at java.lang.System.loadLibrary(System.java:993)<br />at HelloWorld.<clinit>(HelloWorld.java:11)</strong>

這個錯誤的原因是LD_LIBRARY_PATH環境變數沒有包含目前的目錄,HelloWorld程式無法找到libHelloWorld.so這個庫,解決辦法如下:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD; export CLASSPATH=$CLASSPATH:$PWD; java HelloWorld

這樣就能看到我們想要的結果了:

Hello World!

其實,在產生HelloWorld.h之前,我們就可以先修改好 LD_LIBRARY_PATH、CLASSPATH 這兩個環境變數:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD; export CLASSPATH=$CLASSPATH:$PWD

這樣產生HelloWorld.h 就只需命令: javah –jni HelloWorld; 運行HelloWorld只需命令: java HelloWorld 了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.