- 浏览: 15025 次
最新评论
c/c++调用java
- 博客分类:
- 技术杂绘
c/c++调用java
2011年06月30日
一直以来,不喜欢半懂不懂的干事情,读代码的时候发懵了,所以找了下c++调用java的方式方法,作了些删减,摘了下来。
C/C++要调用JAVA程序,必须先加载JAVA虚拟机,由JAVA虚拟机解释执行class文件。为了初始化JAVA虚拟机,JNI提供了一系列的接口函数,通过这些函数方便地加载虚拟机到内存中。
1.加载虚拟机:
函数:jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void args);
参数说明:JavaVM **pvm JAVA虚拟机指针
JNIEnv *env是贯穿整个调用过程的一个参数,因为后面的所有函数都需要这个参数,
2.获取指定对象的类定义:
有两种方法可获得类定义,一是在已知类名的情况使用FindClass来获取;
二是通过对象直接得到类定义GetObjectClass
3.获取要调用的方法:
获得非静态方法:
jmethodID (JNICALL *GetMethodID)(JNIEnv *env, jclass clazz, const char *name, const char *sig);
获得静态方法:
jmethodID (JNICALL *GetStaticMethodID)(JNIEnv *env, jclass class, const char *name, const char *sig);
JNIEnv *env初始化是得到的JNI环境;
jclass class前面已获取到的类定义;
const char *name方法名;
const char *sig 签名。方法的定义,我们知道JAVA支持多态,同名方法通过第四个参数来定位得到具体的方法,这就是签名。
4.调用JAVA类方法:
函数:CallObjectMethod(JNIEnv *env, jobject obj, jmethodID mid);
函数:CallStaticObjectMethod((JNIEnv *env, jobject obj, jmethodID mid);
5.获得类属性的定义:
jfieldID (JNICALL *GetFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);
静态属性:
jfieldID (JNICALL *GetStaticFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);
6.数组处理:
要创建数组首先要知道类型及长度,JNI提供了一系列的数组类型及操作的函数如:
NewIntArray、NewLongArray、NewShortArray、NewFloatArray、NewDoubleArray、NewBooleanArray、NewStringUTF、
NewCharArray、NewByteArray、NewString,访问通过GetBooleanArrayElements、GetIntArrayElements等函数。
7.异常:
由于调用了Java的方法,会产生异常。这些异常在C/C++中无法通过本身的异常处理机制来捕捉到,但可以通过JNI一些函数来获取Java中抛出的异常信息。
8.多线程调用
我们知道JAVA是非常消耗内存的,我们希望在多线程中能共享一个JVM虚拟机,真正消耗大量系统资源的是JAVA虚拟机jvm而不是虚拟机环境env,jvm是允许多个线程访问的,但是虚拟机环境只能被创建它本身的线程所访问,而且每个线程必须创建自己的虚拟机环境env。
这就是发财代码里为什么要Attach和Detach的原因,是为共用java层创建的虚拟机。所以发财代码里没有:
jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void args);
JNI提供了两个函数来提供虚拟机共享:AttachCurrentThread和DetachCurrentThread。便于子线程创建自己的虚拟机环境。
// 类MyTest为了测试JNI使用C/C++调用JAVA
public class MyTest {
// 测试如何访问静态的基本类型属性
//演示对象型属性
public String helloword;
public MyTest() {
this("JNI演示类");
}
//构造函数
public MyTest(String msg) {
System.out.println("构造函数:" + msg);
this.helloword = msg;
}
//该方法演示如何调用动态方
public String HelloWord() {
System.out.println("JAVA-CLASS:MyTest method:HelloWord:" + helloword);
return helloword;
}
//演示异常的捕捉
public void throwExcp() throws IllegalAccessException {
throw new IllegalAccessException("exception occur.");
}
}
用反汇编工具javap在命令行运行:javap -s -p MyTest ,在我自己的windows命令行下看到:
C代码testjava.c:
#include
#include
/*C字符串转JNI字符串*/
jstring stoJstring(JNIEnv* env, const char* pat)
{
jclass strClass = (*env)->FindClass(env,"Ljava/lang/String;");
jmethodID ctorID = (*env)->GetMethodID(env,strClass, "", "([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env,strlen(pat));
(*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = (*env)->NewStringUTF(env,"utf-8");
return (jstring)(*env)->NewObject(env,strClass, ctorID, bytes, encoding);
}
/*JNI字符串转C字符串*/
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env,"java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"utf-8");
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr, mid, strencode);
jsize alen = (*env)->GetArrayLength(env,barr);
jbyte* ba = (*env)->GetByteArrayElements(env,barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
(*env)->ReleaseByteArrayElements(env,barr, ba, 0);
return rtn;
}
int main(int argc, char** argv) {
int res;
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
/*设置初始化参数*/
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=.";
options[2].optionString = "-verbose:jni"; //用于跟踪运行时的信息
/*版本号设置不能漏*/
vm_args.version=JNI_VERSION_1_2;//jdk版本1.2
vm_args.nOptions = 3;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (res FindClass(env, "MyTest");
if (cls == 0)
{
fprintf(stderr, "FindClass failed\n");
(*jvm)->DestroyJavaVM(jvm);
fprintf(stdout, "Java VM destory.\n");
return;
}
/*获取构造函数,用于创建对象*/
/***1.1可用""作为构造函数, 1.2用""参数中不能有空格"(Ljava/lang/String;)V"*/
mid = (*env)->GetMethodID(env,cls,"","(Ljava/lang/String;)V");
assert (0 != mid);
fprintf(stderr, "GetMethodID \n");
if (mid == 0)
{
fprintf(stderr, "GetMethodID failed\n");
(*jvm)->DestroyJavaVM(jvm);
fprintf(stdout, "Java VM destory.\n");
return;
}
fprintf(stderr, "GetMethodID OK\n");
/*创建对象*/
const char str[]="this is a test for c call java";
jobject obj = (*env)->NewObject (env, cls, mid, stoJstring(env, str));
//jobject obj = (*env)->NewObject(env, cls, mid, 0);
/*如果mid为0表示获取方法定义失败*/
fprintf(stderr, "NewObject OK\n");
/*获取方法ID*/
mid=(*env)->GetMethodID(env,cls,"HelloWord","()Ljava/lang/String;");
if (mid == 0)
{
fprintf(stderr, "GetMethodID 'HelloWord' failed\n");
(*jvm)->DestroyJavaVM(jvm);
fprintf(stdout, "Java VM destory.\n");
return;
}
fprintf(stderr, "GetMethodID 'HelloWord' OK\n");
/*调用动态方法*/
jstring msg = (*env)-> CallObjectMethod(env, obj, mid);
/*
如果该方法是静态的方法那只需要将最后一句代码改为以下写法即可:
jstring msg = (*env)-> CallStaticObjectMethod(env, cls, mid);
*/
/*捕捉异常*/
if ((*env)->ExceptionOccurred(env))
{
(*env)->ExceptionDescribe(env);
return ;
}
/*销毁JAVA虚拟机*/
(*jvm)->DestroyJavaVM(jvm);
fprintf(stdout, "Java VM destory.\n");
}
编译:
gcc -o testjava testjava.c -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -L${JAVA_HOME}/jre/lib/i386/client -ljvm
运行结果:
GetMethodID
GetMethodID OK
[Dynamic-linking native method java.io.FileOutputStream.writeBytes ... JNI]
MyTest:this is a test for c call java
NewObject OK
GetMethodID 'HelloWord' OK
JAVA-CLASS:MyTest method:HelloWord:this is a test for c call java
Java VM destory.
上面是一个非常简单的例子,你还可以访问类属性,访问静态方法。这样在C中就能跟JAVA里一样调用它的类、方法、访问它的属性
本文摘自CSDN博客:http://blog.csdn.net/xhs_lh04/archive/2008/10/01/3006828.aspx
发表评论
-
[.net] 关于.net线程问题总结(二)
2012-01-20 01:45 330[.net] 关于.net线程问题总结(二) 2011年01 ... -
加速你的hibernate引擎
2012-01-20 01:45 703加速你的hibernate引擎 20 ... -
Hello Android 第三版 (二)
2012-01-20 01:45 672Hello Android 第三版 (二) 2010年09月 ... -
MySQL的优化(本文是Monty在O'Reilly Open Source Convention 2000大会上的演讲)(摘自老叶的博客,有删改)
2012-01-20 01:45 636MySQL的优化(本文是Monty在O'Reilly Open ... -
一个对Winsock完成端口模型封装的类
2012-01-20 01:45 792一个对Winsock完成端口模型封装的类 2011年01月0 ... -
VB窗口图表化
2012-01-19 09:33 617VB窗口图表化 2011年04月20日 '本模块为实现托 ... -
VB 两小时
2012-01-19 09:33 697VB 两小时 2011年09月25日 Option Ex ... -
使用 Shell 属性及方法
2012-01-19 09:33 834使用 Shell 属性及方法 2 ... -
VB获取QQ2011安装路径
2012-01-19 09:33 851VB获取QQ2011安装路径 2011年05月23日 V ... -
VB关机代码
2012-01-19 09:33 789VB关机代码 2011年07月20日 .首先在Form1 ... -
转载:OpenGL显示文字
2012-01-17 02:08 817转载:OpenGL显示文字 2010年07月03日 本课 ... -
面试题讲评
2012-01-17 02:08 670面试题讲评 2011年03月14日 面试了几家公司,只有 ... -
主流嵌入式操作系统介绍(一)
2012-01-17 02:08 1717主流嵌入式操作系统介绍(一) 2010年08月13日 h ... -
AIX平台TONGLINK/Q安装与配置
2012-01-17 02:08 1598AIX平台TONGLINK/Q安装与配 ... -
柬埔寨攻略―签证、机票
2012-01-15 21:35 759柬埔寨攻略―签证、机票 2010年01月05日 一、签证 ... -
如何培养一年级学生良好的学习习惯
2012-01-15 21:35 573如何培养一年级学生良 ... -
培养一年级学生良好学习习惯
2012-01-15 21:35 534培养一年级学生良好学 ... -
094小学科学教育
2012-01-15 21:35 494094小学科学教育 2009年11月10日 全国2009 ...
相关推荐
Android中C/C++调用Java代码
详细请见文档说明c/c++调用java方法
VIII. C/C++调用JAVA类 58 一、 加载虚拟机: 59 二、 获取指定对象的类定义: 59 三、 获取要调用的方法: 59 四、 调用JAVA类方法: 60 五、 获得类属性的定义: 60 六、 数组处理: 60 七、 异常: 60 八、 多线程...
Android JNI c/c++调用java的实例 近期通过研究SDL源码 得出Android JNI c/c++调用Java 无需新建虚拟机,这样省去很多步骤,这样调用Android JNI会变得非常容易,大家看下简单实例: 具体步骤如下 第一步获得:两个...
基于Eclipse开发NDK ,开发C ,C++ 和 Java的源码,可以查看Java调用c/c++, 和c/c++调用Java的内容
c/c++调用java,这个是混合编程实例
NDK开发时,C/C++调用Java的函数的一些案例; 传递int类型参数: https://blog.csdn.net/niuba123456/article/details/80978500 传递String类型参数: https://blog.csdn.net/niuba123456/article/details/80978916 ...
从 C/C++ 中调用 Java 代码,有一下几个步骤: 1.创建 JVM。调用 JNI_CreateJavaVM()。 2.寻找要调用的类。调用 FindClass()。 3.找到要调用的方法。调用 GetStaticMethodID()/GetMethodID()。 4.运行方法。...
JNI开发Java和C/C++互相传递List集合, 可以参考: Java从C/C++获取List集合对象:https://blog.csdn.net/niuba123456/article/details/80994166 Java传递List集合对象到C/C++ ...
C/C++中访问Java方法 C/C++中访问Java父类的方法 C/C++中访问/修改Java变量 Java中访问C/C++方法 Java中访问/修改C/C++变量 动态方式实现: C/C++中访问Java方法 C/C++中访问Java父类的方法 C/C++中访问/修改Java...
JNI允许运行在虚拟机的Java程序能够与其它语言(例如C和C++)编写的程序或者类库进行相互间的调用。同时JNI提供的一整套的API,允许将Java虚拟机直接嵌入到本地的应用程序中。图1是Sun站点上对JNI的基本结构的描述
java调用C/C++全过程 JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。 JAVA通过JNI调用本地...
C++调用Java参考代码: 对于C/C++调用Java相对来说有点麻烦。不过思路很简单。
项目中使用两种so打包技术Android.mk和Cmake默认为Cmake,实现了简单的C/C++和Java互通
Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用 http://blog.csdn.net/u014702653/article/details/71141423
一个C/C++ 代码调用 java 变量、方法、成员变量的Demo
通过jni完成java调用c/c++,包含c/c++生成Dll动态库
本教程主要讲解java中如何调用C/C++,C/C++中如何调用java,并带Demo和调试指南
包中含有一个简单的java工程(eclipse)和一个C++工程(VS2013),C++工程有调用java工程的jar包。我会另外写个文档介绍如何调用jar包,在文档原创文档里,自己找