AndroidStudio下JNI开发(easy+1.0)之字符串转换关系
来源:互联网 发布:win10删除多余的网络2 编辑:程序博客网 时间:2024/05/22 12:03
几个提示,直接c++回调java
env->GetObjectClass
env->GetMethodID
env->NewStringUTF
env->CallVoidMethod
类型转换表
JAVA基础类型与C++之间的对应表
这一点可以从jni.h头文件中定义看到:
typedef unsigned char jboolean; /* unsigned 8 bits */typedef signed char jbyte; /* signed 8 bits */typedef unsigned short jchar; /* unsigned 16 bits */typedef short jshort; /* signed 16 bits */typedef int jint; /* signed 32 bits */typedef long long jlong; /* signed 64 bits */typedef float jfloat; /* 32-bit IEEE 754 */typedef double jdouble; /* 64-bit IEEE 754 */由上面的JNI定义代码可以看到,基础类型都是根据Java类型大小等价转换的。因此在使用Java传递过来的基础类型或者返回Java中的基础类型都可以直接使用。比如:
JNIEXPORT jint JNICALLJava_com_example_wastrel_test_Test_BaseTypeTest(JNIEnv *env, jclass type,jint i) { return i+5;}
Java引用类型与C++之间的对应表
/* * Reference types, in C++ */class _jobject {};class _jclass : public _jobject {};class _jstring : public _jobject {};class _jarray : public _jobject {};class _jobjectArray : public _jarray {};class _jbooleanArray : public _jarray {};class _jbyteArray : public _jarray {};class _jcharArray : public _jarray {};class _jshortArray : public _jarray {};class _jintArray : public _jarray {};class _jlongArray : public _jarray {};class _jfloatArray : public _jarray {};class _jdoubleArray : public _jarray {};class _jthrowable : public _jobject {};typedef _jobject* jobject;typedef _jclass* jclass;typedef _jstring* jstring;typedef _jarray* jarray;typedef _jobjectArray* jobjectArray;typedef _jbooleanArray* jbooleanArray;typedef _jbyteArray* jbyteArray;typedef _jcharArray* jcharArray;typedef _jshortArray* jshortArray;typedef _jintArray* jintArray;typedef _jlongArray* jlongArray;typedef _jfloatArray* jfloatArray;typedef _jdoubleArray* jdoubleArray;typedef _jthrowable* jthrowable;typedef _jobject* jweak;
使用JNIEnv完成数据之间的转换
这里只说明引用对象之间的转换,因为对于普通类型,Java与C++是互通的。
String的传递
这里将String单独拿出来讲解,因为String在Java中有着超高的使用频次,JNIEnv对String有相对应的转换函数。JNI里的函数定义如下:
/**转换成unicode相关函数 */jstring NewString(const jchar*, jsize);jsize GetStringLength(jstring);const jchar* GetStringChars(jstring, jboolean* isCopy);void ReleaseStringChars(jstring, const jchar*);/** 转换成UTF-8相关函数 */jstring NewStringUTF(const char*);jsize GetStringUTFLength(jstring);const char* GetStringUTFChars(jstring, jboolean* isCopy);void ReleaseStringUTFChars(jstring, const char*);
当从 JNI 函数 GetStringChars中返回得到字符串B时,如果B是原始字符串java.lang.String 的拷贝,则isCopy被赋值为JNI_TRUE。如果B和原始字符串指向的是JVM中的同一份数据,则 isCopy被赋值为 JNI_FALSE。
当isCopy值为JNI_FALSE时,本地代码决不能修改字符串的内容,否则JVM中的原始字符串也会被修改,这会打破 JAVA语言中字符串不可变的规则。
通常,因为你不必关心JVM是否会返回原始字符串的拷贝,你只需要为 isCopy传递NULL作为参数。
/Java中定义Native函数 public native static String strConcat(String str1,String str2);//生成C++函数并用C++实现字符串连接功能#include "string.h"JNIEXPORT jstring JNICALL Java_com_example_wastrel_test_Test_strConcat (JNIEnv *env, jclass clazz, jstring str1, jstring str2){ //将jstring转换成const char*指针,使用const修饰符表示其内容不可被修改 const char* c1=env->GetStringUTFChars(str1, NULL); const char* c2=env->GetStringUTFChars(str2, NULL); //计算新字符串的长度 int size=strlen(c1)+strlen(c2); //创建一个新的字符串,这里长度+1是为了使字符串有结尾标记'\0' char * n_char=new char[size+1]; //利用C标准库提供的字符串操作方法对字符串进行连接,这里需要include"string.h"头文件 strcpy(n_char,c1); strcat(n_char,c2); //将生成的新字符串转换成UTF的jstring jstring rs=env->NewStringUTF(n_char); //删除刚刚分配的内存 避免引起内存泄漏 delete [] n_char; //通知JVM虚拟机Native代码不在持有字符串的引用,说明白点,就是告诉虚拟机我不使用它了,你可以回收了。 //因为在JVM中如果对象被引用,那么对象将不会被回收。 //这里为什么要传递jstring和生成的char*呢?是因为char*有可能是jstring的拷贝,如果是拷贝,那么char*就应该被删除。 env->ReleaseStringUTFChars(str1,c1); env->ReleaseStringUTFChars(str2,c2); return rs;}//然后我们在Java中调用该函数print(Test.strConcat("里约奥运",",中国加油"));
注:本处以及往后代码中使用的print函数仅仅是把结果追加显示在界面上的TextView上代码如下:
private void print(String str){ tv.append(str+"\n");}运行结果:
基础数据的数组传递
数组传递跟字符串传递一样,Native收到的都是引用的形式,因此JNIEnv也提供了一些列的方法来完成数据的转换。因为不同数据类型之间的调用方式基本一致,此处使用int型数组作为讲解,int[]传递到Native后收到的是jintArray对象。
//获得数组的长度,该方法适用于所有jarray对象jsize GetArrayLength(jarray array)//在本地创建一个jint数组,这个数组只能通过SetIntArrayRegion赋值。jintArray NewIntArray(jsize length);//将jintArray转换成jint指针jint* GetIntArrayElements(jintArray array, jboolean* isCopy);//取出数组中的部分元素放在buf里void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf);//给jintArray按区间赋值void SetIntArrayRegion(jintArray array, jsize start, jsize len,const jint* buf);//释放jntArray,第一个参数表示传过来的jintArray,第二参数表示获取到的本地数组指针//第三个参数需要重点说明,该参数有三个取值:0、JNI_COMMIT、JNI_ABORT//取值 零(0) 时,更新数组并释放所有元素;//取值 JNI_COMMIT 时,更新但不释放所有元素;//取值 JNI_ABORT 时,不作更新但释放所有元素;//一般实际应用中取0较多void ReleaseIntArrayElements(jintArray array, jint* elems,jint mode);
例子1:来自JNI的int数组
//Java中定义Native函数,size表示返回数组的大小public native static int[] getIntArray(int size);//生成Native函数并实现方法#include "stdlib.h"#include "time.h"//定义随机数产生宏 表示产生0~x之间的随机数#define random(x) (rand()%x)JNIEXPORT jintArray JNICALL Java_com_example_wastrel_test_Test_getIntArray (JNIEnv *env, jclass clazz, jint size){ //用时间变量初始化随机数产生器 srand((int)time(0)); jint* rs=new jint[size]; for (int i=0;i<size;i++) { //调用宏产生0~100的随机数 rs[i]=random(100); } //通过JNIEnv的NewIntArray方法new一个jintArray对象 jintArray array=env->NewIntArray(size); //把产生的随机数值赋值给jintArray env->SetIntArrayRegion(array,0,size,rs); return array;}
//Java中调用函数int []rs=Test.getIntArray(10);print("来自于JNI的Int数组");print(IntArrayToString(rs));/**将int[]转换成逗号分隔便于显示的辅助函数*/private String IntArrayToString(int[] ints){ StringBuilder str=new StringBuilder(); str.append('['); for (int i:ints) { str.append(i); str.append(','); } str.deleteCharAt(str.length()-1); str.append(']'); return str.toString();}
运行结果:
例子2:使用JNI对例1返回的数组进行排序
//声明Java Native函数,参数为int[] public native static void sortIntArray(int []ints);//实现C++函数JNIEXPORT void JNICALL Java_com_example_wastrel_test_Test_sortIntArray (JNIEnv *env, jclass clazz, jintArray array){ //获得传递过来的数组长度 jsize size=env->GetArrayLength(array); //将数组转换成Java指针 jint* jints=env->GetIntArrayElements(array,NULL); //简单的冒泡排序 for (int i = 0; i <size-1 ; ++i) { for (int j = 0; j <size-1-i ; ++j) { if(jints[j]<jints[j+1]) { int t=jints[j]; jints[j]=jints[j+1]; jints[j+1]=t; } } } //将排序结果更新到Java数组中,第三个参数等于0表明更新到原数组并释放所有元素 env->ReleaseIntArrayElements(array,jints,0); return;}//在Java中调用print("通过JNI对int数组排序:");Test.sortIntArray(rs);print(IntArrayToString(rs));这里可以看到,我们并没有返回数组,而是通过ReleaseIntArrayElements函数将结果更新到Java数组中。随之我们在Java中的数组值已经变更。
运行结果:
其他基础类型数组的传递
其他基础类型中的数组传递与int[]几乎一致,函数名更换成各自的类型即可。这里不在过多叙述,我想有了上面的例子,很容易明白别的基础数据类型传递使用。
0 0
- AndroidStudio下JNI开发(easy+1.0)之字符串转换关系
- AndroidStudio下JNI开发(easy+1.0)之自动编译
- AndroidStudio下JNI开发(easy+1.0)之Logcat
- AndroidStudio下JNI开发(easy+1.0)之签名
- AndroidStudio下JNI开发(easy+1.0)之Java对象的传递与修改
- AndroidStudio下JNI开发之 libmobi
- AndroidStudio下jni开发
- JNI开发流程(androidstudio)
- AndroidStudio下的jni开发细节
- [JNI]开发之旅(9)JNI函数字符串处理
- AndroidStudio下的JNI
- AndroidStudio使用jni开发
- AndroidStudio Jni 开发初识
- AndroidStudio jni 开发
- Androidstudio工具下的JNI开发环境搭建
- 在AndroidStudio下JNI开发的详细步骤
- AndroidStudio NDK开发 之 jni生成so文件
- AndroidStutio JNI/NDK开发(easy)
- js中Object常用方法和属性
- oracle 数据回滚到指定时间点 命令语句
- [美剧赏析] 权力的游戏<Game of Thrones>完全赏析 (3-4)
- HDU 1878欧拉回路
- IP 回顾
- AndroidStudio下JNI开发(easy+1.0)之字符串转换关系
- 内部接口和内部类的区别
- ios各种设备尺寸相对应的像素
- .bat文件运行后不退出的解决方案
- Comparator和Comparable
- SV进程间通进的几个名词
- Android 图片下载工具类:BitmapUtil
- python(四)上:列表生成式、生成器、迭代器和内置函数
- 关于NSDate的比较方便的方法收集以后还会继续更新