JNI之C++调用Java类 ——java.lang.String
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/n",txt); //打印到控制台
return;
}
参数JNIEnv *env,是JNI里最重要的变量。Java.exe创建JVM,之后JVM生成一个env,该env相当于JVM内的Session,可以完成创建Java对象,调用类方法,获得类的属性等等。
在这里env将方法的参数Str从JNI的jstring类型转换为常数char数组。
4.编译
cl /Ic:/j2sdk 1.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="-Xmx 128m ";
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
尽管本文的代码很有意思,但我还没有想到有什么价值,以及应用到实际项目中的理由。
JNI之C++调用Java类 ——java.lang.String相关推荐
- jni调用java类_JNI之C++调用Java类 —— java.lang.String
JNI之C++调用Java类 -- java.lang.String 为什么要用C++调用Java类?很难回答,写着文章只是觉得JNI很有意思.于是开始编写一段使用VC++在Windows系统里调用j ...
- excel字段自动java类,Java 接口自动化系列--工具类之Excel测试数据解析封装
在进行数据解析时,先来看看excel测试数据格式,这里采用接口和测试数据分离的方式,即分为两个sheet页签分别存放接口信息,用例信息 excel封装成对象步骤 1.导入easypoi的坐标 2.加载 ...
- Java 类java.security.spec.PKCS8EncodedKeySpec 实例源码
项目:Alpine 文件:KeyManager.java /*** Saves a key pair.** @param keyPair the key pair to save* @throw ...
- 什么是写一个java类,Java什么是类?class的相关介绍
本章给大家带来Java什么是类?class的相关介绍,让大家了解关于类(class)的一些知识.有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助.class Point{ construc ...
- Linux中的Java类,Java基础入门学习-Java中类的属性
Java基础入门学习-Java中类的属性 发布时间:2006-05-27 00:46:15来源:红联作者:WWW Public.private.protected显示了三种类中的属性和服务的类型,pu ...
- data image java,类 java.awt.image.DataBuffer 的使用 (Java 2 Platform SE 6)
Raster.DataBuffer dataBuffer, int w, int h, int scanlineStride, int[] bankIndices, int[] bandOffsets ...
- Java安全(一) : java类 | 反射
给个关注?宝儿! 给个关注?宝儿! 给个关注?宝儿! 关注公众号:b1gpig信息安全,文章推送不错过 1.java基础 Java平台共分为三个主要版本Java SE(Java Platform, S ...
- 05.【Java】字符串(String与StringBuffer)
一.String类 1.字符串的特点 字符串是常量,创建后不会被修改 字符串可以显示任意文字的信息 在Java中,单引号扩起来的叫做字符,双引号扩起来的叫做字符串 2.声明字符串 字符串是常量,他可以 ...
- 高效开发:java对象转化成String类型的四种方法
方法1:采用 Object#toString()方法 请看下面的例子: Object object = getObject(); System.out.println(object.toString( ...
最新文章
- C++——auto、decltype、返回类型后置、模板别名:using =、nullptr
- JVM调优总结(五)-调优方法(转载)
- TypeScript 枚举指南
- PHP系统管理mongodb,MongoDB的日常维护管理
- Json转化的三种方式
- [LeetCode] Three Sum题解
- mac电脑怎么配置adb环境变量
- 华氏度和摄氏度的相互转化
- iOS更新系统服务器出错,iPhone 更新失败怎么办?更新 iOS 常见的错误代码及解决方法...
- 从Unity商店下载的插件存放的位置
- 20届icoding 实验1
- 神经网络和算法的关系,神经网络的算法有哪些
- 学校人事管理系统python实现
- 如何解决PS“不能完成请求,因为意外的遇到文件尾”?
- 分布式 PostgreSQL 集群(Citus)官方示例 - 多租户应用程序实战
- UnityStandardAsset工程、源码分析_2_赛车游戏[玩家控制]_车辆核心控制
- 2022 全球网络黑产常用攻击方法 Top 10
- [python爬虫] 正则表达式使用技巧及爬取个人博客实例
- 【精】LintCode领扣算法问题答案:1086. 重复字符串匹配
- 红队笔记之渗透测试流程以及各环节技术纲要
热门文章
- JVM笔记——根据黑马jvm课程课件+自己总结
- WeBankBlockchain-Data-Reconcile---基于区块链的对账组件
- 2.Mac电脑操作使用git的方法
- java中阿里短信服务(附带随机短信验证码生成类) --菜鸟小回
- 已解决(doc转docx):pywintypes.com_error: (-2147221005, ‘无效的类字符串‘, None, None)
- 大量ACM/ICPC书籍与网站资源
- Python:字符串操作1(去掉空格)
- css3四个花瓣,css3实现花瓣loading效果(keyframes+animation+transform)
- 如何禁用计算机防病毒程序,永远关闭电脑系统自带的杀毒软件的操作步骤吧!...
- 从Mobile5升级到Moble6