首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

JNI之C++调用Java种

2013-01-06 
JNI之C++调用Java类Java类需要在虚拟机上运行,也就不是原生的,同样.NET Framework也不是原生的。JNI也就是J

JNI之C++调用Java类
Java类需要在虚拟机上运行,也就不是原生的,同样.NET Framework也不是原生的。JNI也就是Java原生接口。关于JNI的规范,以及为什么要使用它,它能做些什么,都在http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html里记述着。
    JNI是规范,它规定了虚拟机的接口,而把具体的实现留给开发者。

    JVM的实现不是唯一的,目前存在很多种Java虚拟机,Sun Hotspot,IBM JDK,还有HP的,Kaffe等等。最流行的就是Sun的Hotspot,最复杂的就是IBM JDK,这是IBM的一贯作风。本文不讨论JVM的实现,只关注JNI。如果您安装了Sun的JDK,您就能在[JAVA_HOME]/include目录下找到jni.h。这个头文件就是虚拟机的唯一接口,你可以调用它声明的函数创建一个JVM。
    在说明C++调用Java类之前,我想先演示一下如果编写Java Native Method。
1.编写带有Native方法的Java类

org.colimas.jni.test;public class JniTest{    static { System.loadLibrary("JniTestImpl"); }  //JVM调用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"); //调用原生方法    }}

2.使用javah生成c语言头文件。
javah -jni org.colimas.jni.test.JniTest

目录里多了一个org_colimas_jni_test_JniTest.h文件,打开文件,内容如下:
* 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 __cplusplusextern "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代码实现原生方法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 ",txt); //打印到控制台       return;}

参数JNIEnv *env,是JNI里最重要的变量。Java.exe创建JVM,之后JVM生成一个env,该env相当于JVM内的Session,可以完成创建Java对象,调用类方法,获得类的属性等等。

在这里env将方法的参数Str从JNI的jstring类型转换为常数char数组。
4.编译
cl  /Ic:j2sdk1.4.2_10include /Ic:j2sdk1.4.2_10includewin32 /c  JniTestImpl.c
5.连接为DLL
link /dll JniTestImpl.obj
6.设置PATH
set PATH=C:MyProjectColimasCDJNIMyJNI;%PATH%
7.运行
java org.colimas.jni.test.JniTest返回结果

hello JVM
结束
    以上是实现Java原生方法的开发过程,下面进入正题,使用C++调用Java的java.lang.String类。
1. Object类出创建JVM。

使用Java类之前必须要创建JVM环境。JDK由java.exe来完成。本文有Object类的静态方法BeginJVM来创建,用EndJVM来关闭。

创建JVM之后会在创建2个变量,分别是JNIEnv* env和JavaVM* jvm,JNIEnv上文已经说明,JavaVM,顾名思义,代表Java虚拟机,用它来关闭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;//创建JVMbool Object::BeginJVM(){    JavaVMOption options[3];    JavaVMInitArgs vm_args;    //各种参数    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;    //创建JVM,获得jvm和env    int res = JNI_CreateJavaVM(&jvm,(void **)&env, &vm_args);    return true;}bool Object::EndJVM(){    //关闭JVM    jvm->DestroyJavaVM();    return true;}

2. C++的String类调用java.lang.String类方法

编写C++版的String类,调用java String类方法。调用的方法如下:
    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://与要调用的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();};

实现:
#include "stdafx.h"#include "String.h"#include "jni.h"using namespace std;jclass clazz;    //全局变量,用来传递classjobject object;  //全局变量,用来传递objectString::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)构造体    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;    //创建一个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表示 参数为int型,返回char型。详细参见JNI规范    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;    //调用charAt    jchar z = Object::env->CallCharMethod(object,mid,i);    //返回结果。    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表示参数为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;    //调用方法    jint z=Object::env->CallIntMethod(object,mid,jstr);    //返回结果    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;    //传入参数,调用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...{        //创建JVM        Object::BeginJVM();        String test("hello");        //调用replaceAll        const char *result = test.replaceAll("l","z");        //返回结果        cout<< result <<endl;        //关闭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

运行结果如下:

invoking method

invoking method

hezzo

Press any key to continue

热点排行