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

/* 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

#include "org_colimas_jni_test_JniTest.h" //javah生成的头文件

#include

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

在这里env将方法的参数Str从JNI的jstring类型转换为常数char数组。

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.设置PATH

set PATH=C:\MyProject\Colimas\CD\JNI\MyJNI;%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,"", "(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" <

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 <

//关闭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

尽管本文的代码很有意思,但我还没有想到有什么价值,以及应用到实际项目中的理由。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/onlymilan/archive/2006/07/20/947652.aspx

jni调用java类_JNI之C++调用Java类 —— java.lang.String相关推荐

  1. java.lang.String 的 + 号操作,这个谜终于要解开了!

    作者:丶Pz   来源:https://www.cnblogs.com/panzi/p/11956782.html 在之前的面试经历中,对于String的考察还是挺频繁的,大致考察以下几个知识点: S ...

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

    JNI之C++调用Java类 --java.lang.String 为什么要用C++调用Java类?很难回答,写着文章只是觉得JNI很有意思.于是开始编写一段使用VC++在Windows系统里调用ja ...

  3. jni 调用java接口_JNI 调用 JAVA 接口

    JNI 调用 JAVA 接口 介绍 JNI 是本地语言编程接口.它允许运行在JVM中的Java代码和用C.C++或汇编写的本地代码相互操作. 由于一些加密等情况的需要,需要在 so 层获取一些信息用于 ...

  4. cocos2d-x 调用java_cocos2d-x中通过Jni实现Java与C++的互相调用

    cocos2d-x中通过Jni实现Java与C++的互相调用. cocos2d-x用开发者提供了一个类JniHelper,提供了java与c++之间互调的jni解决方案. 笔者所开发的"史上 ...

  5. android java调用参数,如何从命令行调用Android JNI函数并传递Java对象参数

    一.前言 当我们对某个使用原生库(native library)的恶意软件或者应用进行分析或渗透测试时,如果能够对库函数进行隔离和执行是再好不过的事情,这样做我们就可以使用其自身的代码来调试对抗恶意软 ...

  6. Android JNI实现Java与C/C++互相调用,以及so库的生成和调用(JNI方式调用美图秀秀so)

    前言 关于Android Studio如何继承JNI开发环境,请阅读上一篇博文 Android CMake集成JNI开发环境本篇博文将结合实例分别讲解Android中Java如何调用C/C++的方法, ...

  7. java实现进程管理,Java调用批处理或可执行文件和Runtime、Process类实现Java版进程管理器...

    Java调用批处理或可执行文件 用Java编写应用时,有时需要在程序中调用另一个现成的可执行程序或系统命令,这时可以通过组合使用Java提供的Runtime类和Process类的方法实现.下面是一种比 ...

  8. jni c java互相调用_通过JNI实现Java和C++的相互调用

    评论 # re: 通过JNI实现Java和C++的相互调用 2008-07-29 14:14 Always BaNg. 不错,把字符转换也一并讲了吧,比如UTF-8的处理,USC-2与MBCS转换等. ...

  9. java中如何使用反射调用方法以及获得类中的属性

    使用反射获取类中的方法: 1):获取方法所在类的字节码对象. 2):获取方法. ------------------------------------------------------------ ...

最新文章

  1. php的v_PHPV是什么意思
  2. AGG第二课 代码框架以及命名规则
  3. uni-app读取html缓存,uni-app同步缓存值 设置 读取 删除(示例代码)
  4. wxWidgets:wxRibbonGallery类用法
  5. 宣布 Azure Backup 支持备份 Windows Server 2008
  6. python类属性初始化_Python:如何模拟类属性初始化函数
  7. bash: vim: command not found
  8. 输入一批整数,输出最大最小值,输入0结束
  9. python字符串驻留机制_Python中的字符串驻留
  10. pymongo的常用操作
  11. 8051单片机实现与GSM通讯
  12. 百度网址安全中心拦截解除的办法分享
  13. SAP CO T-Code.
  14. Oracle DUL Data Unloader数据恢复工具信息汇总
  15. java到大数据学习路线
  16. 「建模学习」游戏中的场景建模,原来是靠3D扫描建模技术完成?
  17. 服务器内存与台式机内存区别
  18. 数据库内外联接查询语句
  19. 怎么把MySQL数据库卸载干净
  20. 一文了解深度学习实战——预测篇

热门文章

  1. html清除div虚线,纯CSS去除按钮以及链接点击时虚线
  2. 纵坐标是横的还是竖的_纠结地板是横铺还是竖铺好?别瞎折腾了,迎着光铺才是最正确的!...
  3. 知识点:图说 Mysql 权限管理
  4. 17秋 软件工程 团队第五次作业 Alpha Scrum12
  5. Phonegap 环境配置
  6. C++ 四种类型转换
  7. 装饰者模式(Decorator)
  8. 机房收费管理系统 之 总结
  9. 多功能的图像超分辨模型:用于盲图像超分辨的非对称卷积神经网络
  10. 高效大规模图像搜索开源实现