藍森林首頁 | 返回主頁 | 本站地圖 | 站內搜索 | 聯繫信箱 |
 您目前的位置:首頁 > 自由軟件 > 技術交流 > 應用編程


    

藍森林 http://www.lslnet.com 2006年6月6日 10:18


如何在C/C++中調用Java(1)

轉自
http://developer.ccidnet.com/pub/disp/Article?columnID=295&articleID=38068&pageNO=1

本文沒有格式化
如果想看的話最好到原文出處看

這裡介紹了一個C/C++中調用JAVA的方法

如何在C/C++中調用Java(1)
作者:劉冬    本文選自:開放系統世界——賽迪網  2003年02月17日  

Java跨平台的特性使Java越來越受開發人員的歡迎,但也往往會聽到不少的抱怨:用Java開發的圖形用戶窗口界面每次在啟動的時候都會跳出一個控制台窗口,這個控制台窗口讓本來非常棒的界面失色不少。怎麼能夠讓通過Java開發的GUI程序不彈出Java的控制台窗口呢?其實現在很多流行的開發環境例如JBuilder、Eclipse都是使用純Java開發的集成環境。這些集成環境啟動的時候並不會打開一個命令窗口,因為它使用了JNI(Java Native Interface)的技術。通過這種技術,開發人員不一定要用命令行來啟動Java程序,可以通過編寫一個本地GUI程序直接啟動Java程序,這樣就可避免另外打開一個命令窗口,讓開發的Java程序更加專業。

JNI允許運行在虛擬機的Java程序能夠與其它語言(例如C和C++)編寫的程序或者類庫進行相互間的調用。同時JNI提供的一整套的API,允許將Java虛擬機直接嵌入到本地的應用程序中。圖1是Sun站點上對JNI的基本結構的描述。






圖1 JNI基本結構描述圖


本文將介紹如何在C/C++中調用Java方法,並結合可能涉及到的問題介紹整個開發的步驟及可能遇到的難題和解決方法。本文所採用的工具是Sun公司創建的 Java Development Kit (JDK) 版本 1.3.1,以及微軟公司的Visual C++ 6開發環境。


環境搭建


為了讓本文以下部分的代碼能夠正常工作,我們必須建立一個完整的開發環境。首先需要下載並安裝JDK 1.3.1,其下載地址為「http://java.sun.com」。假設安裝路徑為C:\JDK。下一步就是設置集成開發環境,通過Visual C++ 6的菜單Tools→Options打開選項對話框如圖2。






圖2 設置集成開發環境圖


將目錄C:\JDK\include和C:\JDK\include\win32加入到開發環境的Include Files目錄中,同時將C:\JDK\lib目錄添加到開發環境的Library Files目錄中。這三個目錄是JNI定義的一些常量、結構及方法的頭文件和庫文件。集成開發環境已經設置完畢,同時為了執行程序需要把Java虛擬機所用到的動態鏈接庫所在的目錄C:\JDK \jre\bin\classic設置到系統的Path環境變量中。這裡需要提出的是,某些開發人員為了方便直接將JRE所用到的DLL文件直接拷貝到系統目錄下。這樣做是不行的,將導致初始化Java虛擬機環境失敗(返回值-1),原因是Java虛擬機是以相對路徑來尋找所用到的庫文件和其它一些相關文件的。至此整個JNI的開發環境設置完畢,為了讓此次JNI旅程能夠順利進行,還必須先準備一個Java類。在這個類中將用到Java中幾乎所有有代表性的屬性及方法,如靜態方法與屬性、數組、異常拋出與捕捉等。我們定義的Java程序(Demo.java)如下,本文中所有的代碼演示都將基於該Java程序,代碼如下:

package jni.test;
/**
* 該類是為了演示JNI如何訪問各種對像屬性等
* @author liudong
*/
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.");
}
}




初始化虛擬機


本地代碼在調用Java方法之前必須先加載Java虛擬機,而後所有的Java程序都在虛擬機中執行。為了初始化Java虛擬機,JNI提供了一系列的接口函數Invocation API。通過這些API可以很方便地將虛擬機加載到內存中。創建虛擬機可以用函數 jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args)。對於這個函數有一點需要注意的是,在JDK 1.1中第三個參數總是指向一個結構JDK1_ 1InitArgs, 這個結構無法完全在所有版本的虛擬機中進行無縫移植。在JDK 1.2中已經使用了一個標準的初始化結構JavaVMInitArgs來替代JDK1_1InitArgs。下面我們分別給出兩種不同版本的示例代碼。

在JDK 1.1初始化虛擬機:

#include <jni.h>;
int main() {
JNIEnv *env;
JavaVM *jvm;
JDK1_1InitArgs vm_args;
jint res;
/* IMPORTANT: 版本號設置一定不能漏 */
vm_args.version = 0x00010001;
/*獲取缺省的虛擬機初始化參數*/
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* 添加自定義的類路徑 */
sprintf(classpath, "%s%c%s",
vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
vm_args.classpath = classpath;
/*設置一些其他的初始化參數*/
/* 創建虛擬機 */
res = JNI_CreateJavaVM(&jvm,&env,&vm_args);
if (res < 0) {
  fprintf(stderr, "Can't create Java VM\n");
  exit(1);
}
/*釋放虛擬機資源*/
(*jvm)->;DestroyJavaVM(jvm);
}



JDK 1.2初始化虛擬機:

/* invoke2.c */
#include <jni.h>;
int main() {
int res;
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
vm_args.version=JNI_VERSION_1_2;//這個字段必須設置為該值
/*設置初始化參數*/
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=.";
options[2].optionString = "-verbose:jni";        //用於跟蹤運行時的信息
/*版本號設置不能漏*/
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 3;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (res < 0) {
  fprintf(stderr, "Can't create Java VM\n");
  exit(1);
}   
(*jvm)->;DestroyJavaVM(jvm);
fprintf(stdout, "Java VM destory.\n");
}



為了保證JNI代碼的可移植性,建議使用JDK 1.2的方法來創建虛擬機。JNI_CreateJavaVM函數的第二個參數JNIEnv *env,就是貫穿整個JNI始末的一個參數,因為幾乎所有的函數都要求一個參數就是JNIEnv *env。


訪問類方法


初始化了Java虛擬機後,就可以開始調用Java的方法。要調用一個Java對象的方法必須經過幾個步驟:

1.獲取指定對象的類定義(jclass)

有兩種途徑來獲取對象的類定義:第一種是在已知類名的情況下使用FindClass來查找對應的類。但是要注意類名並不同於平時寫的Java代碼,例如要得到類jni.test.Demo的定義必須調用如下代碼:

jclass cls = (*env)->;FindClass(env, "jni/test/Demo");        //把點號換成斜槓



然後通過對像直接得到其所對應的類定義:

jclass cls = (*env)->; GetObjectClass(env, obj);
//其中obj是要引用的對象,類型是jobject



2.讀取要調用方法的定義(jmethodID)

我們先來看看JNI中獲取方法定義的函數:

jmethodID (JNICALL *GetMethodID)(JNIEnv *env, jclass clazz, const char *name,
const char *sig);
jmethodID (JNICALL *GetStaticMethodID)(JNIEnv *env, jclass class, const char
*name, const char *sig);

如何在C/C++中調用Java(1)

好,很好



Copyright © 1999-2000 LSLNET.COM. All rights reserved. 藍森林網站 版權所有。 E-mail : webmaster@lslnet.com