原文地址: http://blog.csdn.net/sunchaoenter/article/details/6598719
最近項目中需要使用JNI,所以研究了一下,其中遇到過不少問題,總結一下,讓遇到同樣問題的人可以得到解決。
在C/C++中調用Java的方法一般分為五個步驟:初始化虛擬機器、擷取類、擷取類的方法、建立類對象、調用方法和退出虛擬機器。
下面寫一個小程式測試一下:
Java代碼:
view plaincopy to clipboardprint?
- 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.");
- }
- }
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語言代碼,裡面有注釋,這裡先不詳細說明,主要先跑起來再說:
view plaincopy to clipboardprint?
- #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