從 C/C++ 程式調用 Java 代碼

來源:互聯網
上載者:User

JNI允許您從機器碼內調用 Java 類方法。

要做到這一點,通常必須使用 Invocation API 在機器碼內建立和初始化一個 JVM。

下列是您可能決定從 C/C++ 代碼調用Java 代碼的典型情況:

    1.希望實現的這部分代碼是平台無關的,它將用於跨多種平台使用的功能。

    2.需要在本機應用程式中訪問用 Java 語言編寫的代碼或程式碼程式庫。

    3.希望從機器碼利用標準 Java 類庫。

從C/C++ 程式調用 Java 代碼的四個步驟:

1.編寫 Java 代碼。

    這個步驟包含編寫一個或多個 Java 類,這些類實現(或調用其它方法實現)您想要訪問的功能。

2.編譯 Java 代碼。

    在能夠使用這些 Java 類之前,必須成功地將它們編譯成位元組碼。

3.編寫 C/C++ 代碼。

    這個代碼將建立和執行個體化 JVM,並調用正確的 Java 方法。

4.運行本機 C/C++ 應用程式。

    將運行應用程式以查看它是否正常工作。我們還將討論一些用於處理常見錯誤的技巧。

步驟 1:編寫Java 代碼
我們從編寫一個或多個 Java 原始碼檔案開始,這些檔案將實現我們想要本機 C/C++ 代碼使用的功能。
下面顯示了一個 Java 程式碼範例JNI_cCalljava_test.java:

package test;public class JNI_cCalljava_test {   public static int intMethod(int n) {      return n*n;  }public static boolean booleanMethod(boolean bool) { return !bool;}}

註:JNI_cCalljava_test.java 實現了兩個 static Java 方法:intMethod(intn) 和 booleanMethod(boolean bool)(分別在第 3 行和第 7 行)。static方法是一種不需要與對象執行個體關聯的類方法。調用 static方法要更容易些,因為不必執行個體化對象來調用它們。

步驟 2:編譯Java 代碼

接下來,我們將 Java 代碼編譯成位元組碼。

完成這一步的方法之一是使用隨SDK 一起提供的Java 編譯器 javac。使用的命令是:

JNI_cCalljava_test.java

或者直接在eclipose中編寫儲存即可

步驟 3:編寫 C/C++ 代碼

即使是在本機應用程式中運行,所有 Java 位元組碼也必須在 JVM 中執行。

因此 C/C++ 應用程式必須包含用來建立和初始化 JVM 的調用。

為了方便我們,SDK 包含了作為共用庫檔案(jvm.dll 或 jvm.so)的 JVM,這個庫檔案可以嵌入到本機應用程式中。


讓我們先從瀏覽一下 C 和 C++ 應用程式的整個代碼開始,然後對兩者進行比較。

帶有嵌入式 JVM的 C 應用程式:

#include <jni.h>//jni.h檔案包含在 C 代碼中所需要的 JNI 的所有類型和函數定義#ifdef _WIN32#define PATH_SEPARATOR ';'#else#define PATH_SEPARATOR ':'#endif//1.包括準備本機應用程式以處理 Java 代碼//2.將 JVM 嵌入本機應用程式//3.然後從該應用程式內找到並調用 Java 方法。int main(){/*接下來,聲明所有希望在程式中使用的變數。JavaVMOption options[] 具有用於 JVM 的各種選項設定。當聲明變數時,確保所聲明的JavaVMOption options[] 數組足夠大,以便能容納您希望使用的所有選項。在本例中,我們使用的唯一選項就是類路徑選項。因為在本樣本中,我們所有的檔案都在同一目錄中,所以將類路徑設定成目前的目錄。可以設定類路徑,使它指向任何您希望使用的目錄結構。*/JavaVMOption options[1];JNIEnv *env;JavaVM *jvm;JavaVMInitArgs vm_args;/*JNIEnv *env          表示 JNI 執行環境。JavaVM jvm             是指向 JVM 的指標,我們主要使用這個指標來建立、初始化和銷毀 JVM。JavaVMInitArgs vm_args 表示可以用來初始化 JVM 的各種 JVM 參數。*/long status;jclass cls;jmethodID mid;jint square;jboolean not;/*avaVMInitArgs 結構表示用於 JVM 的初始化參數。在執行 Java 代碼之前,可以使用這些參數來定製運行時環境。正如您所見,這些選項是一個參數,而 Java 版本是另一個參數。按如下所示設定了這些參數:*//*為 JVM 設定類路徑,以使它能找到所需要的 Java 類。在這個特定樣本中,因為 Sample2.class 和Sample2.exe 都位於同一目錄中,所以將類路徑設定成目前的目錄。我們用來為 Sample2.c 設定類路徑的代碼如下所示:*/options[0].optionString = "-Djava.class.path=.";memset(&vm_args, 0, sizeof(vm_args));vm_args.version = JNI_VERSION_1_2;vm_args.nOptions = 1;vm_args.options = options;/*建立 JVM處理完所有設定之後,現在就準備建立 JVM 了。先從調用方法開始如果成功,則這個方法返回零,否則,如果無法建立 JVM,則返回JNI_ERR。*/status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);if (status != JNI_ERR){/*尋找並裝入 Java 類一旦建立了 JVM 之後,就可以準備開始在本機應用程式中運行 Java 代碼。首先,需要使用FindClass() 函數尋找並裝入 Java 類,如下所示:cls 變數儲存執行FindClass() 函數後的結果,如果找到該類,則 cls 變數表示該Java 類的控制代碼,如果不能找到該類,則 cls 將為零。*/cls = (*env)->FindClass(env, "test/JNI_cCalljava_test");printf("test1,cls=%d...\n",cls);if(cls !=0){ /*尋找 Java 方法接下來,我們希望用 GetStaticMethodID() 函數在該類中尋找某個方法。我們希望尋找方法 intMethod,它接收一個 int 參數並返回一個 int。以下是尋找 intMethod 的代碼:*/mid = (*env)->GetStaticMethodID(env, cls, "intMethod", "(I)I");/*mid 變數儲存執行 GetStaticMethodID() 函數後的結果。如果找到了該方法,則 mid 變數表示該方法的控制代碼。如果不能找到該方法,則mid 將為零。*/if(mid !=0){ /*CallStaticIntMethod() 方法接受 cls(表示類)、mid(表示方法)以及用於該方法一個或多個參數。在本例中參數是 int 5。*/square = (*env)->CallStaticIntMethod(env, cls, mid, 5);printf("Result of intMethod: %d\n", square);}mid = (*env)->GetStaticMethodID(env, cls, "booleanMethod", "(Z)Z");if(mid !=0){not = (*env)->CallStaticBooleanMethod(env, cls, mid, 1);printf("Result of booleanMethod: %d\n", not);}}(*jvm)->DestroyJavaVM(jvm);return 0;}elsereturn -1;}

帶有嵌入式 JVM的 C++ 應用程式

#include <jni.h>#ifdef _WIN32#define PATH_SEPARATOR ';'#else#define PATH_SEPARATOR ':'#endifint main(){JavaVMOption options[1];JNIEnv *env;JavaVM *jvm;JavaVMInitArgs vm_args;long status;jclass cls;jmethodID mid;jint square;jboolean not;options[0].optionString = "-Djava.class.path=.";memset(&vm_args, 0, sizeof(vm_args));vm_args.version = JNI_VERSION_1_2;vm_args.nOptions = 1;vm_args.options = options;status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);if (status != JNI_ERR){cls = env->FindClass("Sample2");if(cls !=0){   mid = env->GetStaticMethodID(cls, "intMethod", "(I)I");if(mid !=0){  square = env->CallStaticIntMethod(cls, mid, 5);printf("Result of intMethod: %d\n", square);}mid = env->GetStaticMethodID(cls, "booleanMethod", "(Z)Z")if(mid !=0){  not = env->CallStaticBooleanMethod(cls, mid, 1);printf("Result of booleanMethod: %d\n", not);}}jvm->DestroyJavaVM();return 0;}elsereturn -1;}

C 和 C++ 實現的比較

C 和C++ 代碼幾乎相同;唯一的差異在於用來訪問 JNI 函數的方法。

在 C 中,為了取出函數指標所引用的值,JNI 函數調用前要加一個(*env)-> 首碼。

在 C++ 中,JNIEnv類擁有處理函數指標尋找的內聯成員函數。

因此,雖然這兩行代碼訪問同一函數,但每種語言都有各自的文法,如下所示。

C 文法:

cls = (*env)->FindClass(env, "Sample2");

C++ 文法:

cls = env->FindClass("Sample2");


C 文法:

mid = (*env)->GetStaticMethodID(env, cls, "intMethod", "(I)I");

C++ 文法:

mid = env->GetStaticMethodID(cls, "intMethod", "(I)I");
 

C 文法:

square = env->CallStaticIntMethod(cls, mid, 5);

C++ 文法:

square = (*env)->CallStaticIntMethod(env, cls, mid, 5);

 

C 文法:

(*jvm)->DestroyJavaVM(jvm);

C++ 文法:

jvm->DestroyJavaVM();

步驟 4:運行應用程式

現在準備運行這個 C 應用程式,並確保代碼正常工作。當運行 Sample2.exe 時,應該可以得到如下結果:

windows:

使用vc6.0建一個普通的C語言工程

標頭檔路徑設定同Java調用C語言裡的設定

串連時需要jvm.lib支援

這裡需要右擊建立的工程,單擊設定(Settings),link選項欄將資料庫路徑添加進來



C:"\Program Files"\Java\jdk1.6.0_10\lib\jvm.lib

在下面的project options中加入以上語句,用空格隔開,programe Files用雙引號引起來

運行時需要jvm.dll動態庫的支援,需要在系統內容變數中增加以下路徑:

C:\Program Files\Java\jdk1.6.0_10\jre\bin\server

方法:右擊 我的電腦-》屬性-》進階-》環境變數-》PATH 編輯,在原有環境變數的基礎上增加以上路徑,注意用";"號隔開

將eclipose產生的java代碼放在JNI_cCalljava_test.exe同目錄下(注意按照把報名檔案夾也拷過去)

E:\Sample2>JNI_cCalljava_test.exe
Result of intMethod: 25
Result of booleanMethod: 0

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.