標籤:
在Java代碼中通過JNI調用C函數的步驟如下:
第一步:編寫Java代碼
第二步:編譯Java代碼(javac Java檔案)
第三步:產生C代碼標頭檔(javah java類名,自動產生)
第四步:編寫C代碼(實現C代碼標頭檔裡面的函數)
第五步:產生C共用庫(使用工具編譯產生C共用庫,win下面為dll檔案,Linux下面為so檔案)
第六步:運行Java程式(java 類名)
一、編寫Java代碼
首先編寫調用C語言的Java原始碼HelloJNI.java
public class HelloJNI {native void printHello();native void printString(String str);static {System.loadLibrary("hellojni");}public static void main(String[] args) {// TODO Auto-generated method stubHelloJNI myJNI = new HelloJNI();myJNI.printHello();myJNI.printString("Hello world form printString function!");}}
說明:
1. 在Java類中,使用”native”關鍵字,聲明本地方法,該方法與用C/C++編寫的JNI本地函數相對應。”native”關鍵字告知Java編譯器,在Java代碼中帶有該關鍵字的方法只是聲明,具體由C/C++等其它語言編寫實現。
2. 在Java類中聲明了本地方法之後,接下來,調用System.loadLibrary()方法,載入具體實現本地方法的C運行庫(在Java中載入本地運行庫通常使用靜態塊(static block))。System.loadLibrary()方法載入由字串參數指定的本地庫,在不同作業系統平台下,載入的C運行庫不同。在Window下面,調用System.loadLibrary(“hellojni”),則hellojni.dll會被載入;在Linux下面,則會載入libhellojni.so檔案。
二、編譯Java代碼
使用javac編譯java原始碼
javac HelloJNI.java
三、產生C代碼標頭檔
使用javah自動產生C代碼標頭檔
javah HelloJNI
產生的標頭檔HelloJNI.h見下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloJNI */#ifndef _Included_HelloJNI#define _Included_HelloJNI#ifdef __cplusplusextern "C" {#endif/** Class: HelloJNI* Method: printHello* Signature: ()V*/JNIEXPORT void JNICALL Java_HelloJNI_printHello(JNIEnv *, jobject);/** Class: HelloJNI* Method: printString* Signature: (Ljava/lang/String;)V*/JNIEXPORT void JNICALL Java_HelloJNI_printString(JNIEnv *, jobject, jstring);#ifdef __cplusplus}#endif#endif
四、編寫C代碼
實現C標頭檔中的方法,hellojni.c檔案見下:
#include "HelloJNI.h"#include <stdio.h>JNIEXPORT void JNICALL Java_HelloJNI_printHello(JNIEnv *env, jobject obj){printf("Hello world!\n");return ;}JNIEXPORT void JNICALL Java_HelloJNI_printString(JNIEnv *env, jobject obj, jstring string){const char * str = (*env)->GetStringUTFChars(env,string,0);printf("%s!\n",str);return ;}
說明:
1、GetStringUTFChars ()是JNI函數,用來將Java字串轉換成C語言字串。JNI提供了多種JNI函數,用來處理C字串與Java字串的轉換,具體參見http://blog.csdn.net/qinjuning/article/details/7595104
五、產生C共用庫
在Linux下測試,書寫makefile檔案,編譯剛才所寫的C代碼,產生.so檔案;
makefile檔案見下:
libhellojni.so:hellojni.o makefilegcc -Wall -rdynamic -shared -o libhellojni.so hellojni.ohellojni.o:hellojni.c HelloJNI.hgcc -Wall -c hellojni.c -I./ -I/usr/lib/jdk/include -I/usr/lib/jdk/include/linux -fPICcl:rm -rf *.o *.so
使用make命令編譯
make
說明:
1、產生的so檔案必須命令為libhellojni.so,與java代碼中的System.loadLibrary("hellojni")對應;
2、在編譯時間,必須加上-fPIC,否則,編譯時間報以下錯誤:
/usr/bin/ld: hellojni.o: relocation R_X86_64_32 against `a local symbol‘ can not be used when making a shared object; recompile with -fPIC
hellojni.o: could not read symbols: Bad value
collect2: ld 返回 1
make: *** [hellojni.so] 錯誤 1
3、gcc和rm前面必須是一個tab空格,否則makefile格式不正確;
六、運行java程式
在運行java程式之前,要把產生的so檔案加入LD_LIBRARY_PATH中,如下:
export LD_LIBRARY_PATH=./
否則,在運行java程式的時候報錯,錯誤資訊見下:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no hellojni in java.library.pathat java.lang.ClassLoader.loadLibrary(ClassLoader.java:1738)at java.lang.Runtime.loadLibrary0(Runtime.java:823)at java.lang.System.loadLibrary(System.java:1028)at HelloJNI.<clinit>(HelloJNI.java:7)Could not find the main class: HelloJNI. Program will exit.
運行java程式:
java HelloJNI
結果見下:
Hello world!Hello world form printString function!!
在Java中調用C