您的位置:首页 > 编程语言 > C语言/C++

JNI之C++调用Java类 —— java.lang.String

2008-01-22 09:06 597 查看
JNI之C++调用Java类 —— java.lang.String

为什么要用C++调用Java类?很难回答,写着文章只是觉得JNI很有意思。于是开始编写一段使用VC++在Windows系统里调用java的String类,在C++里调用String类内的一些方法。

JNI已经被开发了很多年,而在我2年多的Java编程时间里从来没有接触过。直到最近研究JVM实现原理才注意到JNI。 JNI既Java Native Interface,Native这个词我见过我认为最恰当的翻译就是原生。原生的意思就是来自系统自己的,原汁原味的东西,例如Win32 API。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类


package 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 __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代码实现原生方法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;




//创建JVM




bool 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; //全局变量,用来传递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)构造体


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: