`
touchinsert
  • 浏览: 1287458 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

阅读更多

JNIC++调用Java

——java.lang.String

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

JNI已经被开发了很多年,而在我2年多的Java编程时间里从来没有接触过。直到最近研究JVM实现原理才注意到JNI JNIJava Native InterfaceNative这个词我见过我认为最恰当的翻译就是原生。原生的意思就是来自系统自己的,原汁原味的东西,例如Win32 APIJava类需要在虚拟机上运行,也就不是原生的,同样.NET Framework也不是原生的。JNI也就是Java原生接口。关于JNI的规范,以及为什么要使用它,它能做些什么,都在http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html里记述着。

JNI是规范,它规定了虚拟机的接口,而把具体的实现留给开发者。

JVM的实现不是唯一的,目前存在很多种Java虚拟机,Sun HotspotIBM JDK,还有HP的,Kaffe等等。最流行的就是SunHotspot,最复杂的就是IBM JDK,这是IBM的一贯作风。本文不讨论JVM的实现,只关注JNI。如果您安装了SunJDK,您就能在[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\n",txt); //打印到控制台

return;

}

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

在这里env将方法的参数StrJNIjstring类型转换为常数char数组。

4.编译

cl /Ic:\j2sdk<chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899">1.4.2</chsdate>_10\include /Ic:\j2sdk1.4.2_10\include\win32 /c JniTestImpl.c

5.连接为DLL

link /dll JniTestImpl.obj

6.设置PATH

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

7.运行

java org.colimas.jni.test.JniTest

返回结果

hello JVM

结束

以上是实现Java原生方法的开发过程,下面进入正题,使用C++调用Javajava.lang.String类。

1. Object类出创建JVM

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

创建JVM之后会在创建2个变量,分别是JNIEnv* envJavaVM* jvmJNIEnv上文已经说明,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="-Xmx<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="128" unitname="m">128m</chmetcnv>";

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,获得jvmenv

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;

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics