Java 呼叫C語言JNI庫(Hello World例項)
要在java中呼叫c語言的庫,一直覺得很不可思議,但是Java提供了JNI這個東西,這也就變得可能了. 作為一個碼農,我們還是從最簡單的 Hello World開始吧.
首先說一下我們想要做的事情. 在c語言中定義一個 void sayHello()函式(列印Hello World);然後在Java中呼叫這個函式顯示Hello Word.
現在分別從Java和C語言兩部分說明:
1. Java 部分
我們首先定義一個HelloNative,在其中申明sayHello函式,函式要申明為Native 型別的.如下:
public class HelloNative { publicnative void sayHello(); }
編譯這個類,生成class檔案:
javac HelloWorld.java
利用javah生成需要的h檔案
javah HelloNative
生成的 h檔案大概如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloNative */ #ifndef _Included_HelloNative #define _Included_HelloNative #ifdef __cplusplusextern "C" { #endif /* * Class: HelloNative * Method: sayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloNative_sayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
我們可以看一下上面自動生成的程式,程式include了jni.h,這個標頭檔案在 $JAVA_HOME下的include資料夾下. 還可以發現生成的函式名是在我們的函式名前面加上了Java_HelloNative.
2. C語言部分
根據上面生成的h檔案編寫相應的程式碼實現,如我們建立一個 HelloNative.cpp用來實現顯示Hello World的函式.如下:
#include <stdio.h> #include "HelloNative.h" JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *, jobject) { printf("Hello World!\n"); }
程式碼編寫完成之後,我們再用g++(#add,一定不要用gcc,會報錯)編譯成庫檔案,命令如下;
g++ -fPIC -I/usr/lib/jvm/java-7-openjdk-i386/include -I/usr/lib/jvm/java-7-openjdk-i386/include/linux -shared -o libHelloNative.so HelloNative.cpp
這樣就會在當前目錄下生成一個libHelloNative.so的庫檔案.這時我們需要的庫已經生成,在C語言下的工作已經完成了.
接下來我們需要在Java中編寫一個程式測試一下.在程式前,我們需要將我們的庫載入進去.載入的方法是呼叫Java的 System.loadLibrary("HelloNative");
public class TestNative { static { try { System.loadLibrary("HelloNative"); //沒有lib字首 } catch(UnsatisfiedLinkError e) { System.out.println( "Cannot load hello library:\n " + e.toString() ); } } public static void main(String[] args) { HelloNative test = new HelloNative(); test.sayHello(); } }
但是再我們編譯後,執行的時候,問題又出現了.
Cannot load hello library: java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloNative.sayHello()V at HelloNative.sayHello(Native Method) at TestNative.main(TestNative.java:13)
載入庫失敗,但是我們的庫明明就是放在當前資料夾下的,怎麼會載入失敗呢?
我們用System.getProperty("java.library.path")檢視,發現java.library.path中並不u存在當前的目錄.主要有以下的幾個解決辦法:
1) 將生成的庫複製到java.library.path有的路徑中去,當然這樣不是很好
2) 設定環境變數export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ,將當前的目錄加入到LD_LIBRARY_PATH中
3) 設定java 的選項,將當前的目錄加入到其中 .java -Djava.library.path=. $LD_LIBRARY_PATH
這樣之後我們的程式就能夠成功的運行了.可以看見顯示的"Hello World!"了