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 __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
分享到:
相关推荐
**C++调用Java方法** 1. **加载Java类:** 使用`JNIEnv`指针的`FindClass`方法,传入要查找的Java类的全名(包括包名)。 2. **获取方法ID:** 使用`GetMethodID`,需要提供类的ID、方法的签名以及方法名。方法...
总结,C++库封装JNI接口实现Java调用C++涉及的主要步骤包括:声明Java中的本地方法,生成JNI头文件,编写C++实现,编译成库,最后在Java中加载并调用。这个过程需要理解Java和C++之间的数据类型转换,以及如何在两种...
7. **C++调用Java**: - 通过`JNIEnv`指针,C++可以查找并调用Java对象的方法,访问字段,甚至创建新的Java对象。 8. **构建流程**: - 使用NDK(Native Development Kit)编译C/C++代码,生成.so文件。 - 将.so...
接下来,C++调用Java类的方法展示了JNI的另一个关键用途。这个例子可能用于集成现有的C++代码到Java应用程序中。流程如下: 1. 创建Java类,并在其中声明需要被C++调用的方法,同样标记为native。 2. 使用javah生成...
本文旨在介绍 Java 和 C++ 之间的互相调用实例,通过 JNI(Java Native Interface)技术,实现 Java 调用 C++ 和 C++ 调用 Java 的操作。下面将对标题、描述、标签和部分内容进行详细说明。 标题:JNI 调用实例...
本文将深入探讨如何使用C++创建Java虚拟机(JVM),并通过JNI来调用Java函数。这是一项技术性很强的任务,需要对C++编程、Java虚拟机的工作原理以及JNI接口有深入的理解。 首先,Java虚拟机(JVM)是Java平台的核心...
Android Studio项目,此Demo实现Java调用C++函数,然后C++函数回调Java方法、纯C++直接调用Java方法,此为github地址链接
在AIX操作系统上,使用C++调用Java类(包)是一种常见的跨语言交互技术,主要依赖于Java Native Interface (JNI)。JNI允许Java代码调用本地(非Java)代码,反之亦然,使得C++和Java可以无缝协作。下面我们将深入...
在这个“jni.zip”压缩包中,我们主要探讨的是如何使用C++通过JNI来调用Java类,这是Java平台跨语言交互的一个重要技术。下面将详细介绍这个过程: 1. **JNI基本结构**: JNI接口定义了一组函数,这些函数允许本地...
在本文中,我们将深入探讨如何在Visual Studio 2019环境下使用C++通过Java Native Interface (JNI)来调用Java代码。JNI是Java平台的一部分,它为Java应用程序提供了与本地代码交互的能力,使得开发者可以将Java应用...
利用JNI技术实现Java中调用C++编写的函数库示例程序源码,并附上参考JNI文档。...详情见本人博客:Java学习之通过JNI调用C/C++编写的dll链接库(图文教程)(http://write.blog.csdn.net/postlist)
总结,C++调用Java通过JNI实现,涉及到JVM的初始化、类加载、方法ID获取、方法调用和资源释放等关键步骤。提供的示例文件展示了这一过程,通过分析和运行这些文件,你可以更深入地理解C++与Java的混合编程实践。
本文将详细讲解在Android Studio 3.0中如何实现C++调用Java以及Java调用C++的过程。 首先,我们需要在Android Studio项目中配置NDK(Native Development Kit),它是Android用于编写和编译C/C++代码的工具集。在...
### C++调用Java代码的JNI实现概述 在软件开发领域,经常会出现不同语言之间相互调用的需求。本文将深入探讨如何使用C++通过JNI(Java Native Interface)调用来实现对Java代码的调用,特别关注于用户身份验证与...
JNI头文件和源代码生成器`javah`用于生成C/C++的头文件,这个头文件定义了Java类中的native方法对应的C/C++函数原型。 在这个DEMO中,我们看到有get()和set()两个方法,这些都是通过JNI调用C/C++实现的。在Java中,...
完整的实现java跨平台调用C程序源码,包含JAVA源码和C源码以及编译后的demo dll。将dll放到jdk bin目录下,java 项目可以直接运行。若要修改dll可以,修改C源码后重新编译生成dll。该demo处理了多线程调用c,全局...
对于C++调用Java而言,需要通过JNI API创建并启动一个Java虚拟机实例,然后通过这个实例访问Java类和方法。 #### 示例:C++调用Java方法 考虑一个简单的示例,其中C++调用一个Java类`WinFile`的`GetFilesFromDir`...
`jobject`参数是Java对象的引用,通常是你调用JNI函数的Java类实例。 为了从Java层调用这个C++函数,我们需要生成JNI接口。SWIG(Simplified Wrapper and Interface Generator)是一个工具,可以帮助我们自动生成...
#### 八、C/C++调用JAVA类 - **加载虚拟机:** - 初始化Java虚拟机。 - **获取指定对象的类定义:** - 使用`FindClass`方法。 - **获取要调用的方法:** - 使用`GetMethodID`方法。 - **调用JAVA类方法:** - ...
本案例探讨的是如何使用C++调用Java函数,这通常涉及到JNI(Java Native Interface)技术。以下是对这个实战项目的详细解释: 首先,我们要理解标题"实战-C++调用Java函数"所涉及的核心知识点。C++是一种强大的系统...