Java世界

          學習筆記

          常用鏈接

          統計

          積分與排名

          天籟村

          新華網

          雅虎

          最新評論

          如何在c++中調用java代碼(轉載)

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

           

          c++調用java其實并不復雜,分為幾個步驟:

           

          在說調用之前,我們先來看看我們需要調用的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. }  

            這是一個很簡單的類,他有一個無參的構造函數,有三個方法,一個帶有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. }  

           

            也是一個很簡單的類,有兩個屬性,還有一個回調函數,主要是想演示一下我們如在C++中獲取該對象以后,進行回調,這也是我們經常會遇到的問題。

           

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

           

          創建jvm

          我們首先需要初始化一些jvm的參數,然后創建出jenv和jvm以便我們之后的調用

           

          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. //設置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);  

           

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

           

          加載調用的java類

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

          當我們成功創建完jvm后,接下來我們找到需要調用的java類

           

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

           

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

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

           

          調用構造函數,創建對象

          像我們在java語言中一樣,我們首先需要調用構造函數創建一個對象實例,然后再進行方法調用,那么在C++中同樣需要我們這么做,當然調用靜態方法例外。

                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調用,這個函數有三個參數,一個是我們之前獲取的jclass對象,第二參數是需要調用的java類中的方法名稱,由于我們是調用構造函數,所以<init>是個固定的寫法,他就是說明我們要調用構造函數,第三參數是調用方法的參數類型,關于這個參數的類型,我們可以使用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()構造函數,在Signature后面就是該方法的參數類型。

          當我們獲取構造函數以后,我們就可以對其進行實例化了,使用NewObject

           

          方法調用

          接下來我們就可以進行方法調用了

          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. }  

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

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

           

          下面我們來說一下如何進行回調

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

          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方法,然后調用該方法,得到一個返回的對象obj,我在代碼里進行一下處理,創建了一個全局引用,如果大家只想把他當做局部變量使用,那么不創建全局引用也可以;然后通過GetObjectClass我們得到了jclass對象,接下來就跟我們之前的過程一樣了,獲取方法,進行調用即可。

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

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

          評論

          # re: 如何在c++中調用java代碼(轉載) 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  回復  更多評論   

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

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


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


          網站導航:
           
          主站蜘蛛池模板: 同仁县| 廉江市| 上栗县| 丰镇市| 长泰县| 丽江市| 阜城县| 墨江| 周宁县| 吉水县| 丘北县| 江北区| 金平| 礼泉县| 洛扎县| 广水市| 垦利县| 枝江市| 铜鼓县| 石柱| 尉犁县| 垫江县| 苍南县| 长顺县| 肥西县| 通江县| 涡阳县| 汉源县| 天镇县| 将乐县| 九寨沟县| 三河市| 岳阳市| 韶关市| 黄大仙区| 东阳市| 宿迁市| 通化市| 乐亭县| 海伦市| 佛教|