Linux下JNI實現

來源:互聯網
上載者:User
文章目錄
  • 什麼是JNI
  • JNI的簡單樣本

最近研究Android,涉及到JNI調用。雖然我對Java語言有所瞭解,但是還沒有接觸過JNI。今天在Unix Center的Ubuntu上面用JNI實現了“經典”的“Hello world”程式。通過這個簡單的程式把JNI的一些小知識進行一下總結。

什麼是JNI

     JNI是Java native interface的簡寫,可以譯作Java原生介面。Java可以通過JNI調用C/C++的庫,這對於那些對效能要求比較高的Java程式無疑是一個福音。

    
使用JNI也是有代價。大家都知道JAVA程式是運行在JVM之上的,可以做到平台無關。但是如果Java程式通過JNI調用了原生的代碼(比如
c/c++等),則Java程式就喪失了平台無關性。最起碼需要重新編譯原生代碼部分。所以應用JNI需要好好權衡,不到萬不得已,請不要選擇JNI,可
以選擇替代方案,比如TCP/IP進行進程間通訊等等。這也是為什麼Google的Android平台的底層雖然用JNI實現,但是他不建議開發人員用JNI來開
發Android上面的應用的原因。將會喪失Android上面的應用程式平台無關性。

JNI的簡單樣本

     下面我就用JNI實現一個經典的“Hello World”程式。該程式在Java中通過JNI調用c函數實現“Hello World”的輸出。建立該程式分為以下步驟:

1、建立一個Java程式(HelloWorld.java)定義原生的c/c++函數。

2、用javac編譯HelloWorld.java產生HelloWorld.class。

3、用javah帶-jni參數編譯HelloWorld.class產生HelloWorld.h檔案,該檔案中定義了c的函數原型。在實現c函數的時候需要。

4、建立HelloWorld.c,實現HelloWorld.h定義的函數。

5、編譯HelloWorld.c產生libHelloWorld.so。

6、在java虛擬機器運行java程式HelloWorld。

     下面我們就一步一步來實現這個程式。

建立HelloWorld.java
class HelloWorld{private native void print();public static void main(String[] args){new HelloWorld().print();}static{System.loadLibrary("HelloWorld");}}

注意print方法的聲明,關鍵字native表明該方法是一個原生代碼實現的。另外注意static程式碼片段的System.loadLibrary調用,這段代碼錶示在程式載入的時候,自動載入libHelloWorld.so庫。

編譯HelloWorld.java

在命令列中運行如下命令:

javac HelloWorld.java

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

產生HelloWorld.h

在命令列中運行如下命令:

javah -jni HelloWorld

在當前檔案夾中會產生HelloWorld.h。開啟HelloWorld.h將會發現如下代碼:

/* 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

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

實現HelloWorld.c

建立HelloWorld.c檔案輸入如下的代碼:

#include <jni.h>#include <stdio.h>#include "HelloWorld.h"JNIEXPORT void JNICALL     Java_HelloWorld_print(JNIEnv *env, jobject obj){printf("Hello World!\n");}

注意必須要包含jni.h標頭檔,該檔案中定義了JNI用到的各種類型,宏定義等。

另外需要注意Java_HelloWorld_print的兩個參數,本例比較簡單,不需要用到這兩個參數。但是這兩個參數在JNI中非常重要。

env代表java虛擬機器環境,Java傳過來的參數和c有很大的不同,需要調用JVM提供的介面來轉換成C類型的,就是通過調用env方法來完成轉換的。

obj代表調用的對象,相當於c++的this。當c函數需要改變調用對象成員變數時,可以通過操作這個對象來完成。

編譯產生libHelloWorld.so

在Linux下執行如下命令來完成編譯工作:

cc -I/usr/lib/jvm/java-6-sun/include/linux/   -I/usr/lib/jvm/java-6-sun/include/    -fPIC -shared -o libHelloWorld.so HelloWorld.c

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

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

運行Java程式HelloWorld

大功告成最後一步,驗證前面的成果的時刻到了:

java HelloWorld

如果你這步發生問題,如果這步你收到java.lang.UnsatisfiedLinkError異常,可以通過如下方式指明共用庫的路徑:

java -Djava.library.path='.' HelloWorld

當然還有其他的方式可以指明路徑請參考《在Linux平台下使用JNI》。

我們可以看到久違的“Hello world!”輸出了。

總結

本文只是一個JNI簡單調用,當然JNI還有很多東西需要學習。如有錯誤之處請不吝指教。

參考文章:

在Linux平台下使用JNI

The Java Native Interface Programmer’s Guide and Specification

JNI編程指南-中文版

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.