最近項目中需要使用JNI,所以研究了一下,其中遇到過不少問題,總結一下,讓遇到同樣問題的人可以得到解決。
在C/C++中調用Java的方法一般分為五個步驟:初始化虛擬機器、擷取類、擷取類的方法、建立類對象、調用方法和退出虛擬機器。
下面寫一個小程式測試一下:
Java代碼:
package jni.test;public class Demo {public static int COUNT = 8;public String msg;private int[] counts;public Demo() {this("預設建構函式");}public Demo(String msg) {System.out.println("<init>:" + msg);this.msg = msg;this.counts = null;}public String getMessage() {return msg;}public int[] getCounts() {return counts;}public void setCounts(int[] counts) {this.counts = counts;}public void throwExcp() throws IllegalAccessException {throw new IllegalAccessException("exception occur.");}}
上面的代碼很好理解,我相信你能看的懂,我就不說了。
下面是C語言代碼,裡面有注釋,這裡先不詳細說明,主要先跑起來再說:
#include <stdio.h>#include <jni.h>#include <stdlib.h>#include <iostream.h>int main() {// 定義用到的變數int res;JavaVM *jvm;JNIEnv *env;JavaVMInitArgs vm_args;JavaVMOption options[3];vm_args.version;// 設定初始化參數options[0].optionString = "-Djava.compiler=NONE";// classpath有多個時,用";"分隔,UNIX下以":"分割。options[1].optionString = "-Djava.class.path=.";// 用於跟蹤運行時的資訊options[2].optionString = "-verbose:jni";// 版本號碼設定不能漏vm_args.version = JNI_VERSION_1_6;vm_args.nOptions = 3;vm_args.options = options;vm_args.ignoreUnrecognized = JNI_TRUE;// 1.初始化虛擬機器res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);if (res < 0){fprintf(stderr, "Can't create Java VM\n");exit(1);}// 2.擷取類jclass cls = env->FindClass("jni/test/Demo");// 3.擷取類的方法jmethodID mid= env->GetMethodID(cls,"getMessage","()Ljava/lang/String;");// 擷取Java的構造方法jmethodID con=env->GetMethodID(cls,"<init>","(Ljava/lang/String;)V");jstring strinit = env->NewStringUTF("Still is coding!");jvalue arg[1];arg[0].l = strinit;//env->AllocObject(cls);// 4.建立類的對象jobject obj = env->NewObjectA(cls,con,arg);// 調用對象的方法jstring msg = (jstring)env-> CallObjectMethod(obj, mid);cout<<msg<<endl;char *str=(char *)env->GetStringUTFChars(msg,JNI_FALSE);printf("%s===",str);// 5.退出虛擬機器jvm->DestroyJavaVM();fprintf(stdout, "Java VM destory.\n");return 0;}
把以上C語言代碼用VC6.0開啟,然後編譯,下面問題就來了,我們一個一個解決。
編譯的時候首先會出現如下問題:
錯誤很明顯,我們上麵包含了jni.h,但是沒找到。這是需要設定一下VC。
Tools->Options->Directories,添加JDK安裝目錄下的兩個目錄,
同時在Library files中添加JDK下面的LIB目錄,如:
點擊OK完成,重新編譯。
好,新問題又來了,看下面描述:
也很明顯,說明沒有找到jvm.lib。繼續設定VC,Project->Settings->Link->Object/library modules中把上述路徑替換為本機實際安裝JDK中的jvm.lib目錄,添加完後如:
點擊OK後重新編譯,呵呵,又來問題了,我很高興啊。
這個問題在網上查了一下,原來是我JDK安裝在Program Files下的問題,因為Program Files路徑中有一個空格,真鬱悶,沒辦法,只好重裝JDK,注意安裝目錄中不能再有空格了。安裝完了,按照上面出現的問題再重新設定一下VC,然後編譯,沒問題,運行,哇靠,又是一個問題:
這個問題可是花了我大半天時間才搞定的,但其實做法很簡單。
看錯描述,是沒找到jvm.dll,網上很多人說直接找到這個檔案把它拷貝到目前的目錄。但是這種方法不可取,因為jvm.dll這個東東還會依賴其他的檔案的,而且它找其它所依賴的檔案是通過相對路徑找的,你直接就搞這麼一個檔案出來,其它的也找不到啊。所以這裡有一個很好的解決方案,就是把D:\Java\jdk1.6.0_23\jre\bin\client這個JDK下的路徑加入Path環境變數,加完之後記得重新用VC開啟CPP檔案,這個很重要,否則,這個問題還是沒有解決。
點擊編譯,運行,如果出現如下畫面,OK,恭喜你,C語言調用Java成功了,下面要做的就是去看代碼,並且瞭解啟動並執行機理了,這個我就不多說了。
原始碼下載:http://download.csdn.net/source/3434985