悟心

          成功不是將來才有的,而是從決定去做的那一刻起,持續(xù)累積而成。 上人生的旅途罷。前途很遠(yuǎn),也很暗。然而不要怕。不怕的人的面前才有路。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            93 隨筆 :: 1 文章 :: 103 評論 :: 0 Trackbacks

          原文出處

          JNI之C++調(diào)用Java類 —— java.lang.String

              為什么要用C++調(diào)用Java類?很難回答,寫著文章只是覺得JNI很有意思。于是開始編寫一段使用VC++在Windows系統(tǒng)里調(diào)用java的String類,在C++里調(diào)用String類內(nèi)的一些方法。

              JNI已經(jīng)被開發(fā)了很多年,而在我2年多的Java編程時間里從來沒有接觸過。直到最近研究JVM實現(xiàn)原理才注意到JNI。 JNI既Java Native Interface,Native這個詞我見過我認(rèn)為最恰當(dāng)?shù)姆g就是原生。原生的意思就是來自系統(tǒng)自己的,原汁原味的東西,例如Win32 API。Java類需要在虛擬機上運行,也就不是原生的,同樣.NET Framework也不是原生的。JNI也就是Java原生接口。關(guān)于JNI的規(guī)范,以及為什么要使用它,它能做些什么,都在http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html里記述著。

              JNI是規(guī)范,它規(guī)定了虛擬機的接口,而把具體的實現(xiàn)留給開發(fā)者。

              JVM的實現(xiàn)不是唯一的,目前存在很多種Java虛擬機,Sun Hotspot,IBM JDK,還有HP的,Kaffe等等。最流行的就是Sun的Hotspot,最復(fù)雜的就是IBM JDK,這是IBM的一貫作風(fēng)。本文不討論JVM的實現(xiàn),只關(guān)注JNI。如果您安裝了Sun的JDK,您就能在[JAVA_HOME]\include目錄下找到j(luò)ni.h。這個頭文件就是虛擬機的唯一接口,你可以調(diào)用它聲明的函數(shù)創(chuàng)建一個JVM。

              在說明C++調(diào)用Java類之前,我想先演示一下如果編寫Java Native Method。

          1.編寫帶有Native方法的Java類

          package org.colimas.jni.test;

          public class JniTest {

              static { System.loadLibrary("JniTestImpl"); }  //JVM調(diào)用JniTestImpl.dll

              public JniTest(){
              }

              //原生方法
              public native void print(String str);

              /**
              * @param args
              */
              public static void main(String[] args) {
                      JniTest test=new JniTest();
                      test.print("hello JVM"); //調(diào)用原生方法
              }
          }

          2.使用javah生成c語言頭文件。

          javah -jni org.colimas.jni.test.JniTest

          目錄里多了一個org_colimas_jni_test_JniTest.h文件,打開文件,內(nèi)容如下:

          /* DO NOT EDIT THIS FILE - it is machine generated */

          #include <jni.h>

          /* Header for class org_colimas_jni_test_JniTest */


          #ifndef _Included_org_colimas_jni_test_JniTest
          #define _Included_org_colimas_jni_test_JniTest
          #ifdef __cplusplus

          extern "C" {

          #endif

          /*
           * Class:     org_colimas_jni_test_JniTest
           * Method:    print
           * Signature: (Ljava/lang/String;)V
           */

          JNIEXPORT void JNICALL Java_org_colimas_jni_test_JniTest_print
            (JNIEnv *, jobject, jstring);

          #ifdef __cplusplus
          }

          #endif
          #endif


          其中的Java_org_colimas_jni_test_JniTest_print就是JniTest類里面的print原生方法的C語言聲明。

          3.編寫C代碼實現(xiàn)原生方法print

          #include <jni.h>
          #include "org_colimas_jni_test_JniTest.h" //javah生成的頭文件
          #include <stdio.h>

          JNIEXPORT void JNICALL Java_org_colimas_jni_test_JniTest_print
            (JNIEnv *env, jobject object,jstring str)
          {
                 //獲得字符串
                 const char * txt=(*env)->GetStringUTFChars(env,str,0);
                 printf("%s\n",txt); //打印到控制臺
                 return;
          }


          參數(shù)JNIEnv *env,是JNI里最重要的變量。Java.exe創(chuàng)建JVM,之后JVM生成一個env,該env相當(dāng)于JVM內(nèi)的Session,可以完成創(chuàng)建Java對象,調(diào)用類方法,獲得類的屬性等等。

          在這里env將方法的參數(shù)Str從JNI的jstring類型轉(zhuǎn)換為常數(shù)char數(shù)組。

          4.編譯

          cl  /Ic:\j2sdk1.4.2_10\include /Ic:\j2sdk1.4.2_10\include\win32 /c  JniTestImpl.c

          5.連接為DLL

          link /dll JniTestImpl.obj

          6.設(shè)置PATH

          set PATH=C:\MyProject\Colimas\CD\JNI\MyJNI;%PATH%

          7.運行

          java org.colimas.jni.test.JniTest

          返回結(jié)果

          hello JVM

          結(jié)束

              以上是實現(xiàn)Java原生方法的開發(fā)過程,下面進(jìn)入正題,使用C++調(diào)用Java的java.lang.String類。

          1. Object類出創(chuàng)建JVM。

          使用Java類之前必須要創(chuàng)建JVM環(huán)境。JDK由java.exe來完成。本文有Object類的靜態(tài)方法BeginJVM來創(chuàng)建,用EndJVM來關(guān)閉。

          創(chuàng)建JVM之后會在創(chuàng)建2個變量,分別是JNIEnv* env和JavaVM* jvm,JNIEnv上文已經(jīng)說明,JavaVM,顧名思義,代表Java虛擬機,用它來關(guān)閉JVM。

          Object類的頭文件

          #include "jni.h"

          class Object
          {
          public:
              static bool BeginJVM();
              static bool EndJVM();
              Object();
              virtual ~Object();

          protected:
              static JNIEnv* env;
              static JavaVM* jvm;
          };

          object.cpp代碼

          #include "stdafx.h"
          #include "JavaClasses.h"
          #include "Object.h"

          Object::Object()
          {}

          Object::~Object()
          {}

          JNIEnv* Object::env=NULL;
          JavaVM* Object::jvm=NULL;

          //創(chuàng)建JVM

          bool Object::BeginJVM()
          {

              JavaVMOption options[3];
              JavaVMInitArgs vm_args;

              //各種參數(shù)
              options[0].optionString="-Xmx128m";
              options[1].optionString="-Verbose:gc";
              options[2].optionString="-Djava.class.path=.";

              vm_args.version=JNI_VERSION_1_2;
              vm_args.options=options;
              vm_args.nOptions=3;

              //創(chuàng)建JVM,獲得jvm和env
              int res = JNI_CreateJavaVM(&jvm,(void **)&env, &vm_args);
              return true;
          }

          bool Object::EndJVM()
          {
              //關(guān)閉JVM
              jvm->DestroyJavaVM();
              return true;
          }

          2. C++的String類調(diào)用java.lang.String類方法

          編寫C++版的String類,調(diào)用java String類方法。調(diào)用的方法如下:

              String  replaceAll(String regex, String replacement);

              boolean endsWith(String str);

              int indexOf(String str);

              int compareTo(String anotherString);

              char charAt(int i);

          String的頭文件:

          class String  :public Object
          {
          public:
          //與要調(diào)用的Java方法名一致。
              const char * replaceAll(char *regex,char *replacement);

              bool endsWith(char * str);

              int indexOf(char * str);

              int compareTo(char *anotherString);

              char charAt(int i);

              String(char *str);

              virtual ~String();
          };

          實現(xiàn):

          #include "stdafx.h"
          #include "String.h"
          #include "jni.h"

          using namespace std;

          jclass clazz;    //全局變量,用來傳遞class
          jobject object;  //全局變量,用來傳遞object
          String::String(char *str)
          {
              jstring jstr;

              if (Object::env ==NULL){
                  cout << "JVM is not created" << endl;
                  exit(-1);
              }

              //獲得java.lang.String類
              clazz=Object::env->FindClass("java/lang/String");

              if (clazz ==0 ){
                  cout << "Class is not found" << endl;
                  exit(-1);
              }

              //獲得String(String str)構(gòu)造體
              jmethodID mid= Object::env->GetMethodID(clazz,"<init>", "(Ljava/lang/String;)V");

              if (mid==0){
                  cerr<< "GetMethodID Error for class" << endl;
                  exit(-1);
              }

              //將字符串封裝為jstring。
              jstr = Object::env->NewStringUTF(str);

              if (jstr == 0) {
                  cerr << "Out of memory" <<endl;
                  exit(-1);
              }

              cout << "invoking method" << endl;

              //創(chuàng)建一個java.lang.String對象。
              object=Object::env->NewObject(clazz,mid,jstr);
          }

          String::~String()
          {}

          char String::charAt(int i)
          {
              if (Object::env ==NULL){
                  cout << "JVM is not created" << endl;
                  exit(-1);
              }

              if (clazz ==0 ){
                  cout << "Class is not found" << endl;
                  exit(-1);
              }

              if (object ==0 ){
                  cout << "String object is not created" << endl;
                  exit(-1);
              }

              jmethodID mid;

              //獲得charAt方法,(I)C表示 參數(shù)為int型,返回char型。詳細(xì)參見JNI規(guī)范
              mid = Object::env->GetMethodID(clazz,"charAt", "(I)C");

              if (mid==0){
                  cerr<< "GetMethodID Error for class" << endl;
                  exit(-1);
              }

              jint ji=i;

              cout << "invoking method" << endl;

              //調(diào)用charAt
              jchar z = Object::env->CallCharMethod(object,mid,i);

              //返回結(jié)果。
              return z;
          }


          int String::compareTo(char *anotherString)
          {

              if (Object::env ==NULL){
                  cout << "JVM is not created" << endl;
                  exit(-1);
              }

              if (clazz ==0 ){
                  cout << "Class is not found" << endl;
                  exit(-1);
              }

              if (object ==0 ){
                  cout << "String object is not created" << endl;
                  exit(-1);
              }

              jmethodID mid;

              //(Ljava/lang/String;)I表示參數(shù)為java.lang.String,返回int
              mid= Object::env->GetMethodID(clazz,"compareTo", "(Ljava/lang/String;)I");

              if (mid==0){
                  cerr<< "GetMethodID Error for class" << endl;
                  exit(-1);
              }

              jstring jstr = Object::env->NewStringUTF(anotherString);
              cout << "invoking method" << endl;

              //調(diào)用方法
              jint z=Object::env->CallIntMethod(object,mid,jstr);

              //返回結(jié)果
              return z;
          }


          int String::indexOf(char *str)
          {
              if (Object::env ==NULL){
                  cout << "JVM is not created" << endl;
                  exit(-1);
              }

              if (clazz ==0 ){
                  cout << "Class is not found" << endl;
                  exit(-1);
              }

              if (object ==0 ){
                  cout << "String object is not created" << endl;
                  exit(-1);
              }

              jmethodID mid;
              mid= Object::env->GetMethodID(clazz,"indexOf", "(Ljava/lang/String;)I");

              if (mid==0){
                  cerr<< "GetMethodID Error for class" << endl;
                  exit(-1);
              }

              jstring jstr = Object::env->NewStringUTF(str);
              cout << "invoking method" << endl;

              jint z=Object::env->CallIntMethod(object,mid,jstr);
              return z;
          }


          bool String::endsWith(char *str)
          {

              if (Object::env ==NULL){
                  cout << "JVM is not created" << endl;
                  exit(-1);
              }

              if (clazz ==0 ){
                  cout << "Class is not found" << endl;
                  exit(-1);
              }

              if (object ==0 ){
                  cout << "String object is not created" << endl;
                  exit(-1);
              }

              jmethodID mid;
              mid= Object::env->GetMethodID(clazz,"endsWith", "(Ljava/lang/String;)Z");

              if (mid==0){
                  cerr<< "GetMethodID Error for class" << endl;
                  exit(-1);
              }

              jstring jstr = Object::env->NewStringUTF(str);
              cout << "invoking method" << endl;

              bool z = Object::env->CallBooleanMethod(object,mid,jstr);
              return z;
          }


          const char * String::replaceAll(char *regex, char *replacement)
          {
              if (Object::env ==NULL){
                  cout << "JVM is not created" << endl;
                  exit(-1);
              }

              if (clazz ==0 ){
                  cout << "Class is not found" << endl;
                  exit(-1);
              }

              if (object ==0 ){
                  cout << "String object is not created" << endl;
                  exit(-1);
              }

              jmethodID mid;
              mid= Object::env->GetMethodID(clazz,"replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

              if (mid==0){
                  cerr<< "GetMethodID Error for class" << endl;
                  exit(-1);
              }

              jvalue array[2];
              jstring jreg = Object::env->NewStringUTF(regex);
              jstring jstr = Object::env->NewStringUTF(replacement);

              array[0].l=jreg;
              array[1].l=jstr;

              cout << "invoking method" << endl;

              //傳入?yún)?shù),調(diào)用replaceAll方法
              jobject z=Object::env->CallObjectMethodA(object,mid,array);
              const char *result=Object::env->GetStringUTFChars((jstring)z, 0);

              return (const char *)result;
          }

          3.測試

          編寫測試代碼

          using namespace std;

          int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
          {
              int nRetCode = 0;

              if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)){
                  cerr << _T("Fatal Error: MFC initialization failed") << endl;
                  nRetCode = 1;
              } else{
                  //創(chuàng)建JVM
                  Object::BeginJVM();

                  String test("hello");

                  //調(diào)用replaceAll
                  const char *result = test.replaceAll("l","z");

                  //返回結(jié)果
                  cout<< result <<endl;

                  //關(guān)閉JVM
                  Object::EndJVM();
              }
              return nRetCode;
          }


          4.運行

          編譯需要 jni.h和jvm.lib文件。

          jni.h在[JAVA_HOME]\include

          jvm.lib在[JAVA_HOME]\lib

          運行需要jvm.dll

          jvm.dll在[JAVA_HOME]\ jre\bin\client

          運行結(jié)果如下:

          invoking method

          invoking method

          hezzo

          Press any key to continue

          盡管本文的代碼很有意思,但我還沒有想到有什么價值,以及應(yīng)用到實際項目中的理由。


          本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/onlymilan/archive/2006/07/20/947652.aspx

          posted on 2009-11-18 11:01 艾波 閱讀(3129) 評論(1)  編輯  收藏 所屬分類: Application 、Java

          評論

          # re: JNI之C++調(diào)用Java類 —— java.lang.String[未登錄] 2013-03-18 09:18 a
          感覺挺有意思的,先大略看了一下。回頭再仔細(xì)研究一下 ,里面感覺能挖出一些很有價值的東西  回復(fù)  更多評論
            

          主站蜘蛛池模板: 江陵县| 洪湖市| 读书| 西林县| 丰都县| 定日县| 北海市| 横峰县| 昭苏县| 江山市| 宁河县| 通海县| 宁城县| 永嘉县| 梧州市| 长垣县| 宜城市| 雅江县| 喀喇| 开封市| 九江县| 铜山县| 绩溪县| 海南省| 东明县| 土默特右旗| 鄂州市| 和林格尔县| 巴林左旗| 巍山| 剑川县| 宝山区| 海晏县| 依安县| 民丰县| 泰顺县| 襄樊市| 台北县| 虎林市| 明水县| 日照市|