JNI编程,C++调用Java
本地代码中使用Java对象
通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和 实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。
下表列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldID或jmethodID。
| 函数 | 描述 |
| GetFieldID | 得到一个实例的域的ID |
| GetStaticFieldID | 得到一个静态的域的ID |
| GetMethodID | 得到一个实例的方法的ID |
| GetStaticMethodID | 得到一个静态方法的ID |
构造一个Java对象的实例
- jclass cls = (*env)->FindClass(env, "Lpackagename/classname;"); //创建一个class的引用
- jmethodID id = (*env)->GetMethodID(env, cls, "", "(D)V"); //注意这里方法的名称是"",它表示这是一个构造函数,而且构造参数是double型的
- jobject obj = (*env)->NewObjectA(env, cls, id, args); //获得一实例,args是构造函数的参数,它是一个jvalue*类型。
首先是获得一个Java类的class引用 (*env)->FindClass(env, "Lpackagename/classname;"); 请注意参数:Lpackagename/classname; ,L代表这是在描述一个对象类型,packagename/classname是该对象耳朵class路径,请注意一定要以分号(;)结束!
然后是获取函数的id,jmethodID id = env->GetMethodID(cls, "", "(D)V"); 第一个是刚刚获得的class引用,第二个是方法的名称,最后一个就是方法的签名了
还是不懂?我曾经如此,请接着看...
难理解的函数签名
JNINativeMethod的定义如下:
- typedef struct {
- const char* name;
- const char* signature;
- void* fnPtr;
- } JNINativeMethod;
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数。
其中比较难以理解的是第二个参数,例如
"()V"
"(II)V"
"(Ljava/lang/String;Ljava/lang/String;)V"
实际上这些字符是与函数的参数类型一一对应的。
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
那其他情况呢?请查看下表:
| 类型 | 符号 |
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | L |
| float | F |
| double | D |
| void | V |
| object对象 | LClassName; L类名; |
| Arrays | [array-type [数组类型 |
| methods方法 | (argument-types)return-type (参数类型)返回类型 |
稍稍补充一下:
1、方法参数或者返回值为java中的对象时,签名中必须以“L”加上其路径,不过此路径必须以“/”分开,自定义的对象也使用本规则
比如说 java.lang.String为“java/lang/String”,com.nedu.jni.helloword.Student为"Lcom /nedu/jni/helloword/Student;"
2、方法参数或者返回值为数组类型时,请前加上[
例如[I表示 int[],[[[D表示 double[][][],即几维数组就加几个[

在本地方法中调用Java对象的方法
1、获取你需要访问的Java对象的类:
- jclass cls = (*env)->GetObjectClass(env, obj); // 使用GetObjectClass方法获取obj对应的jclass。
- jclass cls = (*env)->FindClass(“android/util/log”) // 直接搜索类名,需要是static修饰的类。
2、获取MethodID:
- jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V"); //GetStaticMethodID(…),获取静态方法的ID使用GetMethdoID方法获取你要使用的方法的MethdoID
其参数的意义:
env-->JNIEnv
cls-->第一步获取的jclass
"callback"-->要调用的方法名
"(I)V"-->方法的Signature, 签名同前面的JNI规则。
3、调用方法:
- (*env)->CallVoidMethod(env, obj, mid, depth);// CallStaticIntMethod(….) , 调用静态方法
使用CallVoidMethod方法调用方法。参数的意义:
env-->JNIEnv
obj-->通过本地方法穿过来的jobject
mid-->要调用的MethodID(即第二步获得的MethodID)
depth-->方法需要的参数(对应方法的需求,添加相应的参数)
注:这里使用的是CallVoidMethod方法调用,因为没有返回值,如果有返回值的话使用对应的方法,在后面会提到。
- CallVoidMethod CallStaticVoidMethod
- CallIntMethod CallStaticVoidMethod
- CallBooleanMethod CallStaticVoidMethod
- CallByteMethod CallStaticVoidMethod
现在稍稍明白文章开始构造Java对象那个实例了吧?让我们继续深入一下:
Jni操作Java的String对象
从java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char*不同,所以如果你直接当做char*使用的话,就会出错。因此在使用之前需要将jstring转换成为c/c++中的char*,这里使用JNIEnv提供的方法转换。
const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
(*env)->ReleaseStringUTFChars(env, jstr, str);
这里使用GetStringUTFChars方法将传进来的prompt(jstring类型)转换成为UTF-8的格式,就能够在本地方法中使用了。
注意:在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出。
下面是Jni访问String对象的一些方法:
- GetStringUTFChars 将jstring转换成为UTF-8格式的char*
- GetStringChars 将jstring转换成为Unicode格式的char*
- ReleaseStringUTFChars 释放指向UTF-8格式的char*的指针
- ReleaseStringChars 释放指向Unicode格式的char*的指针
- NewStringUTF 创建一个UTF-8格式的String对象
- NewString 创建一个Unicode格式的String对象
- GetStringUTFLength 获取UTF-8格式的char*的长度
- GetStringLength 获取Unicode格式的char*的长度
下面提供两个String对象和char*互转的方法:
- /* c/c++ string turn to java jstring */
- jstring charToJstring(JNIEnv* env, const char* pat)
- {
- jclass strClass = (*env)->FindClass(env, "java/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);
- }
- /* java jstring turn to c/c++ char* */
- char* jstringToChar(JNIEnv* env, jstring jstr)
- {
- char* pStr = NULL;
- jclass jstrObj = (*env)->FindClass(env, "java/lang/String");
- jstring encode = (*env)->NewStringUTF(env, "utf-8");
- jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");
- jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);
- jsize strLen = (*env)->GetArrayLength(env, byteArray);
- jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);
- if (jBuf > 0)
- {
- pStr = (char*)malloc(strLen + 1);
- if (!pStr)
- {
- return NULL;
- }
- memcpy(pStr, jBuf, strLen);
- pStr[strLen] = 0;
- }
- env->ReleaseByteArrayElements(byteArray, jBuf, 0);
- return pStr;
- }
JNI编程,C++调用Java的更多相关文章
- Android JNI c/c++调用java 无需新建虚拟机
近期通过研究SDL源码 得出android JNI c/c++调用java 无需新建虚拟机: 具体步骤如下 第一步获得:两个参数 JNIEnv和jclass void Java_com_Test_A ...
- Android与JNI(三) ---- c++调用java(转载)
源码下载:JniDemo JNI就是Java Native Interface, 即可以实现Java调用本地库, 也可以实现C/C++调用Java代码, 从而实现了两种语言的互通, 可以让我们更加灵活 ...
- JNI中C调用Java方法
背景需求 我们需要在JNI的C代码调用Java代码.实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用. JNI关键方法讲解. 1. 在同一个类中,调用其他方法 JNIEXPORT v ...
- cocos2d-x笔记5: 通过jni实现C++调用Java
Cocos2d-x的跨平台性很强大,但是偶尔也需要平台的原生API结合. C++在Win32平台下简单的很,C++可以直接用MFC或者调用Win32API. Ios在XCode下直接就能C++和OC混 ...
- Music Studio项目心得--JNI实现C++调用JAVA
这个项目是我參加内蒙古挑战杯的比赛项目,因为时间关系,我没时间实现OpenOMR开源项目由JAVA全然向C++的转换,经过我半个多月的尝试,我将OpenOMR中的1/3的代码改写成C++,只是非常快我 ...
- Android JNI中C调用Java方法
背景需求 我们需要在JNI的C代码调用Java代码.实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用. JNI关键方法讲解. 1. 在同一个类中,调用其他方法 JNIEXPORT v ...
- JNI C反射调用java方法
前面记录了调用C的学习笔记,现在来记录一下C反射调用Java的笔记.JNI开发学习之调用C方法 Android开发中调用一个类中没有公开的方法,可以进行反射调用,而JNI开发中C调用java的方法也是 ...
- JNI由浅入深_7_c调用Java方法一
1.在Java中声明方法 <span style="font-size:14px;">/** * javah -encoding utf-8 -jni com.exam ...
- jni中调用java方法获取当前apk的签名文件md5值
相应的java方法: void getsign(Context context) throws Exception { PackageInfo localPackageInfo = context.g ...
- JNI编程实现(Windows)
上一篇介绍了Linux平台的JNI编程方法,Windows平台的JNI本地调用基本类似,区别就是制作的动态库不同,Linux平台是*.so,Windows平台是*.dll.其中,Windows平台的函 ...
随机推荐
- CentOS下判断自己的VPS是OpenVZ的还是Xen的
一般来说,VPS的虚拟化技术,有Xen.OpenVZ.Xen HVM和VMware这几种,那么,如何判断自己的VPS是基于哪种虚拟化技术的呢? 1.执行:ls /proc/命令,一般Xen的VPS,/ ...
- Android 设置闹铃步骤和基础代码
主要分三步: 1. 设置闹铃时间; 2. 接收闹铃事件广播; 3. 重开机后重新计算并设置闹铃时间; 1. 设置闹铃时间(毫秒) private void setAlarmTime(Context ...
- android异步加载图片
import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; impo ...
- dd命令刻录u盘启动盘
dd命令来刻录windows启动盘 dd if=/ home/avi/Downloads/Win10_English_x64.iso of=/ dev/sdb1 bs=51M; sync dd命令详解 ...
- 了解ThinkPHP(一)
1.项目开发,中,会遇到的问题: 1). 多人开发项目,分工不合理,(html php mysql) 2). 代码风格不一样,后期维护十分困难 3). 项目生命周期十分短,项目生命没有延续性, ...
- java操作office和pdf文件页面列表导出cvs,excel、pdf报表.
在平常的开发中我们常常遇到不仅仅只是导出excel报表的情况.有时候也需要导出pdf或者CSV报 表.其实原理都差不多.刚开始本来不打算也这篇博客介绍这个的.感觉这篇博客和前面的博客有点雷同.原理基本 ...
- source idea of Unit
After the construction of Global environment setting code, there is a convenient way for us in the f ...
- List排序的两种简便方式
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace List ...
- xmlWriter 以UTF-8格式写xml问题
dom4j中的XMLWriter提供以下几种构造方法: XMLWriter() XMLWriter(OutputFormat format) XMLWriter(OutputStream out) X ...
- ubuntu 11.04 源 更新不了,全显示ign、404
原文地址:http://blog.csdn.net/enjio/article/details/11603373 ubuntu 11.04 源 更新不了 分类: 开发相关2013-09-12 14 ...