羅裳輕解,看C++怎樣擁java入懷……

來源:互聯網
上載者:User

前言

在公司裡維護一個網路後台服務端程式,用C++寫的,為了一些靈活性,就想整合個指令碼語言,因為lua似乎沒有什麼庫(或者是我對它比較無知),於是就選了老牌的python。確實噢,這傢伙基本什麼c/c++的庫,都有它的封裝。於是在服務端程式裡,嵌了一個python的解譯器。

可惜事情沒有這麼美好,公司裡會python本來就不多,並且多數僅在入門。

讓學Java的人去學習python? 有木有發現一個現象:學java的程式員們相對都比較自我封閉,基本都不愛再學門語言什麼的,愛穩定,不愛折騰(凡客體?)

好吧,我知道java不是指令碼語言,但反正它編譯成class之後,也是交給c/c++的程式去執行的,這麼一講,它和php,python也差不多,可以當成需要偽編譯一下指令碼語言來看了——呀,我知道python也可以交給net平台或jvm上啟動並執行,s可是這兩個傢伙不是C寫的程式嗎? (最近我寫一句話:世界上只有兩種語言,第一種是C語言,第二種是由C語言寫成的語言,包括C語言)。

一、要做成什麼效果?

1.1 表面作用就這樣——

先讓java程式員,在Eclipse或什麼IDE裡,寫一段java代碼。比如輸出一句 hello world。然後編譯成一個class檔案。

然後在運行我們寫的C++程式,這個程式就執行那一段java代碼,於是在螢幕上輸出一句hello world。

1.2 應用到工作中?

將些功能,交給Java程式員實現,然後通過這套機制,實現一個由C++寫的,已經編譯好的程式,可以將後面業務上需要的一些新功能或變化功能,交給Java實現。這個有實際意義至少: a因為現在的一般公司組成,確實C++程式員比較少。b另外C++要把事情做好,確實比它要把事情做糟的門檻,要高得多。c最後,相比java這樣有很多高階特徵的語言,c++這樣太靜態語言所缺乏一些動態性,有時挺煩人的,比如就沒法通過wsdl來動態產生一個ws的調用代碼(因為沒有反射功能)。


二、準備工作

1.1 C++方面

還是我們常用的 Code::Blocks,也還是 gcc;別的好像也沒有了,當然,用微軟的VC也可以用,只是一些設定的介面不一樣。

1.2 Java方面

一是要裝JDK

JDK和其它c,c++檔案也沒有什麼兩樣,裡面有提供給C,C++的源檔案,有include目錄,有lib目錄好像。

我裝在E盤,路徑是:

E:\Program Files\Java\jdk1.6.0_26 。所以你也就知道了我裝的jdk是什麼版本的。

那些完全沒玩過java的同學注意,可能你的windows裡已經有裝過jvm,比如安裝oracle時,不過jvm只是java虛擬機器,JDK才是你要在jvm上開發的SDK。因為JVM是c寫的,所以它的SDK裡的東東,基本就是C和C++的標頭檔、以及c編譯出來的庫檔案。

二是裝了一個Eclipse

當然,用不用或用什麼IDE都沒關係。

三是寫一段java代碼:

public class Greeting {public void SayHello() {System.out.print("--------Hello C++, I'm Java.----------\n");}}

這樣小的一段代碼,強大的Eclipse在我存檔時,就把它編譯好了。於是我立即在Java工程目錄的bin子目錄下,找到了 Greeting.class檔案。

我沒有寫java的main函數及類,反正那隻是約定好的入口,我們也不需要。我們準備讓自己寫的c++程式來決定要從java的哪個類的哪個方法執行起——說得好像很有得選擇似的,其實本例中,只有一個類,叫Greeting,一個方法,叫SayHello。不是靜態方法,所以調用之前,我們要在c++代碼裡,先建立一個對象,這是後話。

三、C++項目配置

1.1 建立C++項目

步驟一:用code::blocks的嚮導,產生一個空的 c++ 控制台(console)項目,項目名稱命名為 callJava。

1.2 配置JDK標頭檔與庫檔案的搜尋路徑

步驟二:因為要用到jdk的標頭檔和庫檔案,我們又不想把它們都給複製一份到我們callJava的項目目錄下,所以需要設定一下路徑。

     這個方法有很多,最簡單的是直接寫絕對路徑,但我不喜歡這個工程換台器就編譯不了。另外我也不想這樣一個臨時實驗性的工作,專門為java的庫在c::b裡設定一個全域路徑變數。所以我們單獨為這個項目(calljava)設定一個變數好了。

    開啟項目的“build options/構建條件”對話方塊,然後:

  

    然後,就用這個變數名,在項目配置裡,加上 jdk 標頭檔的包含路徑:

  

   最後是 庫檔案的連結路徑,操作類似,只是換了一頁:

  

1.3為項目添加連結庫

   以上配置,等於是讓編譯器知道上哪些個檔案夾裡,去找它所需要 jdk的標頭檔和庫檔案,不過最重要的是,它需要的是檔案?標頭檔當然是在代碼裡寫上,庫檔案呢,我們還需要配置一下。這個例子很簡單,我們只需要一個叫 jvm.lib的檔案:

  

  這個檔案,你可以在一開始說的那個jdk安裝子目錄lib下找到。

四、C++ 代碼

   終於到寫C++代碼了。就直接在嚮導自動產生的main.cpp裡寫吧。

 

#include <iostream>#include <cassert> //assert需要#include <jni.h> //jdk 的標頭檔using namespace std;struct JVMInfo{    JavaVM* jvm;    JNIEnv* env;        JavaVMInitArgs vm_args;        #define VM_OPT_COUNT 3    JavaVMOption options[VM_OPT_COUNT];        JVMInfo()        : jvm(0), env(0)    {        options[0].optionString = const_cast<char *>("-Djava.compiler=NONE");                //classpath有多個時,用";"分隔,UNIX下以":"分割。          options[1].optionString = const_cast<char *>("-Djava.class.path=./demo/bin"); //這裡,至少要包含前面java代碼編譯出來的Greeting.class檔案所在路徑                    //根據我設定的相對路徑,可以推出我的callJava 的C++工程和demo的Java工程所在位置的相對關係。         //用於跟蹤運行時的資訊          options[2].optionString = const_cast<char *>("-verbose:none"); //"-verbose:jni" 換成這個,則jvm啟動時,不會在螢幕上輸出一堆資訊                //JNI版本號碼        vm_args.version = JNI_VERSION_1_6;          vm_args.nOptions = VM_OPT_COUNT;          vm_args.options = options;          vm_args.ignoreUnrecognized = JNI_TRUE;                      }        //建立VM    bool Create()    {        assert(NULL == jvm && NULL == env);                //初始化虛擬機器          return 0 == JNI_CreateJavaVM(&jvm, (void**)(&env), &vm_args);      }        //釋放掉VM    void Destroy()    {        if (jvm)        {            jvm->DestroyJavaVM();                        jvm = 0;            env = 0;        }    }        //一個示範功能    void Demo()    {        assert(NULL != jvm);            do        {            jclass cls = env->FindClass("Greeting");                        #define BREAK_ON_FAIL(fail_condition, fail_msg)  if (fail_condition)  \                               { cerr << fail_msg << endl; break; }                         BREAK_ON_FAIL(!cls, "Can't found class 'Greeting'!");                        //找Greeting類的建構函式            jmethodID ctor = env->GetMethodID(cls, "<init>", "()V");            BREAK_ON_FAIL(!ctor, "Can't found class' ctor !");                        //構建一個Greeting的對象            jobject obj = env->NewObject(cls, ctor);            BREAK_ON_FAIL(!obj, "Can't create a object of 'Greeting'!");                        //找SayHello函數            jmethodID midOfSayHello = env->GetMethodID(cls, "SayHello", "()V");                        BREAK_ON_FAIL(!midOfSayHello, "Can't found class' method 'SayHello()'!");                            //調用obj 的 SayHello 函數            env->CallObjectMethod(obj, midOfSayHello);        }while(false);    }    };int main(){            JVMInfo jvmInfo;        if (!jvmInfo.Create())    {        cerr << "Create JVM fail!" << endl;        return -1;    }       cout << "C++++++++++" << endl;       jvmInfo.Demo();    jvmInfo.Destroy();        cout << "C++++++++++" << endl;     return 0;}

解釋就看注釋吧,或者在網上搜尋一下同類檔案。

四、運行效果

     C++代碼編譯通過,按F9運行……

  

    這隻是一個實驗用的例子,根據在當初擁Python入懷的經驗教訓下,知道要用這種方法來運行大的,包括多線程的java的代碼,還要調用JDK中和並發有關的許多事。

   三行輸出都來自同一個程式,只是其中上下兩行 C++++++++++++++++是來自C++的代碼,中間一句來自Java代碼。現在,我們不再管C++程式,邀請一位Java程式員,讓他協助改改那段 Greet的SayHello函數,就可以直接從運行效果中體現出來修改效果。

  






聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.