Java世界

          學(xué)習(xí)筆記

          常用鏈接

          統(tǒng)計

          積分與排名

          天籟村

          新華網(wǎng)

          雅虎

          最新評論

          如何在c++中調(diào)用java代碼(轉(zhuǎn)載)

          在我們的日常工作中,可能會遇到不同語言之間相互調(diào)用的問題,常見的有java調(diào)用C/C++或者在C/C++中調(diào)用java,我們可以基于sun提供的jni技術(shù)來實現(xiàn)這兩種語言之間的相互調(diào)用,這篇文章來說一下在c++中調(diào)用java的情況,至于java如何調(diào)用c我會在另外一篇文章中單獨講。

           

          c++調(diào)用java其實并不復(fù)雜,分為幾個步驟:

           

          在說調(diào)用之前,我們先來看看我們需要調(diào)用的java類

          public class Test {

          Java代碼  收藏代碼
          1. public Test() {  
          2.       
          3. }  
          4.   
          5. public String getMessage(){  
          6.     return "test ok";  
          7. }  
          8.   
          9. public TestObject getObject() {  
          10.     System.out.println("invoke getObject ok***");  
          11.     TestObject to = new TestObject();  
          12.     to.setName("name");  
          13.     to.setPwd("pwd");  
          14.     return to;  
          15. }  
          16.   
          17. public void test() {  
          18.     System.out.println("%%% invoke test ok***");  
          19. }  

            這是一個很簡單的類,他有一個無參的構(gòu)造函數(shù),有三個方法,一個帶有String返回值的方法,一個是返回一個我們自定義的對象TestObject,另外還有一個沒有返回值的test方法。

          接下來是TestObject類

           

          Java代碼  收藏代碼
          1. public class TestObject {  
          2.     public String name;  
          3.       
          4.     public String pwd;  
          5.   
          6.     public String getName() {  
          7.         return name;  
          8.     }  
          9.   
          10.     public void setName(String name) {  
          11.         this.name = name;  
          12.     }  
          13.   
          14.     public String getPwd() {  
          15.         return pwd;  
          16.     }  
          17.   
          18.     public void setPwd(String pwd) {  
          19.         this.pwd = pwd;  
          20.     }  
          21.       
          22.     public void callback(String content) {  
          23.         System.out.println("%%%call back ok*** cotnent is: " + content);  
          24.         System.out.println("name is: " + name);  
          25.         System.out.println("pwd is: " + pwd);  
          26.     }  
          27.       
          28. }  

           

            也是一個很簡單的類,有兩個屬性,還有一個回調(diào)函數(shù),主要是想演示一下我們?nèi)缭贑++中獲取該對象以后,進行回調(diào),這也是我們經(jīng)常會遇到的問題。

           

          上面看了我們的java測試類,接下來,我們來具體看看如何進行調(diào)用

           

          創(chuàng)建jvm

          我們首先需要初始化一些jvm的參數(shù),然后創(chuàng)建出jenv和jvm以便我們之后的調(diào)用

           

          Cpp代碼  收藏代碼
          1.        JavaVMOption options[1];  
          2. JNIEnv *env;  
          3. JavaVM *jvm;  
          4. JavaVMInitArgs vm_args;  
          5. long status;  
          6. jclass testCls;  
          7. jmethodID testMid;  
          8. jobject testJobj;     
          9. jobject tookitReturnObj;  
          10. //設(shè)置Java類的路徑  
          11. options[0].optionString = "-Djava.class.path=. ;D:\\workspace\\my\\JniTest\\jnitest.jar";  
          12. vm_args.version = JNI_VERSION_1_6;  
          13.        vm_args.nOptions = 1;  
          14.        vm_args.options = options;  
          15.        vm_args.ignoreUnrecognized = JNI_TRUE;  
          16.        status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);  

           

           這里需要指出的是,在設(shè)置classpath的時候,如果需要引用的是jar包,需要把jar包的名稱一并引入,而不能是只指定jar所在目錄,這就會造成一個問題,如果我們依賴的jar很多,那么classPath就需要逐一寫出jar包名稱來,這對于有著幾十個引用jar的項目來說還是會造成一定的麻煩,我推薦大家使用fatjar的一個工具,fatjar可以把依賴的jar合并打成一個jar包,這樣的話,可以減少我們在書寫classpath的過程中,寫太多的jar包,為我們省點事,而且對于維護來講也比較清晰。

           

          加載調(diào)用的java類

          當(dāng)我們創(chuàng)建完jvm后,會得到一個返回值,如果為0說明創(chuàng)建成功,如果否則創(chuàng)建失敗。

          當(dāng)我們成功創(chuàng)建完jvm后,接下來我們找到需要調(diào)用的java類

           

          Cpp代碼  收藏代碼
          1. if (status != JNI_ERR)  
          2. {  
          3.     testCls = env->FindClass("jni/test/Test");  
          4. }  

           

          這里我們要使用Test的一個java類,它所在的包尾jni.test。

          如果加載成功,那么testCls不為0,否則將返回0

           

          調(diào)用構(gòu)造函數(shù),創(chuàng)建對象

          像我們在java語言中一樣,我們首先需要調(diào)用構(gòu)造函數(shù)創(chuàng)建一個對象實例,然后再進行方法調(diào)用,那么在C++中同樣需要我們這么做,當(dāng)然調(diào)用靜態(tài)方法例外。

                testMid = env->GetMethodID( testCls, "<init>", "()V");

          Java代碼  收藏代碼
          1. if (testMid != 0)  
          2. {  
          3.     testJobj = env->NewObject(testCls,testMid);  
          4.     std::cout << "init test class ok" << std::endl;  
          5. }  

            我們可以看到我們首先進行GetMethodID調(diào)用,這個函數(shù)有三個參數(shù),一個是我們之前獲取的jclass對象,第二參數(shù)是需要調(diào)用的java類中的方法名稱,由于我們是調(diào)用構(gòu)造函數(shù),所以<init>是個固定的寫法,他就是說明我們要調(diào)用構(gòu)造函數(shù),第三參數(shù)是調(diào)用方法的參數(shù)類型,關(guān)于這個參數(shù)的類型,我們可以使用javap命令來獲取,具體命令如下:

          javap -p -s jni.test.Test

          然后我們會得到這樣的信息

           

          Java代碼  收藏代碼
          1. Compiled from "Test.java"  
          2. public class jni.test.Test extends java.lang.Object{  
          3. public jni.test.Test();  
          4.   Signature: ()V  
          5. public java.lang.String getMessage();  
          6.   Signature: ()Ljava/lang/String;  
          7. public jni.test.domain.TestObject getObject();  
          8.   Signature: ()Ljni/test/domain/TestObject;  
          9. public void test();  
          10.   Signature: ()V  
          11. }  

           

            我們可以看到Test()構(gòu)造函數(shù),在Signature后面就是該方法的參數(shù)類型。

          當(dāng)我們獲取構(gòu)造函數(shù)以后,我們就可以對其進行實例化了,使用NewObject

           

          方法調(diào)用

          接下來我們就可以進行方法調(diào)用了

          Cpp代碼  收藏代碼
          1. testMid = env->GetMethodID( testCls, "test","()V");  
          2. if (testMid != 0)  
          3. {  
          4.     env->CallVoidMethod(testJobj,testMid);             
          5. }  
          6.   
          7. testMid = env->GetMethodID( testCls, "getMessage","()Ljava/lang/String;");  
          8. if (testMid != 0)  
          9. {  
          10.     jobject msg = env->CallObjectMethod(testJobj,testMid);  
          11.     std::cout << msg << std::endl;  
          12.     printf("msg : %d",msg);  
          13. }  

            上面的代碼里我們調(diào)用兩個方法,分別是test和getMessage,我們都是先調(diào)用GetmethodID來獲取一個jmethodID對象,然后調(diào)用CallXXXMethod來進行調(diào)用,跟java中的反射調(diào)用是一樣的。

          如果我們需要調(diào)用靜態(tài)方法,我們只需先GetStaticMethodID然后調(diào)用CallStaticXXXMethod即可,jni.h中定義了很多Call的方法,比如CallIntMethod,CallBooleanMethod等等,有興趣可以去查看jni.h

           

          下面我們來說一下如何進行回調(diào)

          我們的java測試類Test中有一個getObject的測試方法,得到了一個java對象,我們拿到該獨享后如何進行下一步的調(diào)用呢,其實很簡單,跟咱們之前的例子是類似的

          Cpp代碼  收藏代碼
          1. testMid = env->GetMethodID( testCls, "getObject","()Ljni/test/domain/TestObject;");  
          2.         if (testMid != 0)  
          3.         {  
          4.             jobject obj = env->CallObjectMethod(testJobj,testMid);  
          5.             jobject listener = env->NewGlobalRef(obj);  
          6.             jclass clsj = env->GetObjectClass(listener);  
          7.             jmethodID func = env->GetMethodID(clsj, "callback", "(Ljava/lang/String;)V");  
          8.             if(func != NULL)   
          9.             {  
          10.                 jobject msg1 = env->CallObjectMethod(testJobj,testMid);  
          11.                 env->CallVoidMethod(listener, func, msg1);  
          12.             }  
          13.             std::cout << obj << std::endl;  
          14.             printf("obj : %d",obj);  
          15.         }  
           

          同樣我們通過GetMethodID獲取getObject方法,然后調(diào)用該方法,得到一個返回的對象obj,我在代碼里進行一下處理,創(chuàng)建了一個全局引用,如果大家只想把他當(dāng)做局部變量使用,那么不創(chuàng)建全局引用也可以;然后通過GetObjectClass我們得到了jclass對象,接下來就跟我們之前的過程一樣了,獲取方法,進行調(diào)用即可。

          上面的代碼中我在調(diào)用callback方法前有調(diào)用了一次getObject方法,主要是測試一下,獲取的對象,在進行callback的時候能不能保持其狀態(tài)。經(jīng)驗證是可以的。

          posted on 2012-06-07 09:22 Rabbit 閱讀(7442) 評論(2)  編輯  收藏

          評論

          # re: 如何在c++中調(diào)用java代碼(轉(zhuǎn)載) 2013-12-12 10:51 custjcy

          good post.

          In Java 6 and higher, one can add all jar-files in a specific directory to the classpath using wildcard notation.

          Windows example:
          java -classpath ".;c:\mylib\*" MyApp

          Linux example:
          java -classpath '.:/mylib/*' MyApp  回復(fù)  更多評論   

          # re: 如何在c++中調(diào)用java代碼(轉(zhuǎn)載) 2013-12-12 10:52 custjcy

          http://en.wikipedia.org/wiki/Classpath_(Java)  回復(fù)  更多評論   


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 都江堰市| 崇礼县| 巴林左旗| 蓝山县| 陵川县| 玉溪市| 综艺| 阳山县| 聂拉木县| 延边| 呼玛县| 潮州市| 内黄县| 凭祥市| 贵德县| 合川市| 景泰县| 土默特右旗| 竹山县| 建德市| 咸阳市| 象州县| 方城县| 唐山市| 四川省| 瑞昌市| 克拉玛依市| 南投市| 青州市| 环江| 虎林市| 水富县| 淄博市| 宁远县| 元谋县| 武安市| 白城市| 商城县| 汝阳县| 梅州市| 元谋县|