当前位置:网站首页>【混合编程jni 】第六篇之native 中字符串和数组的操作

【混合编程jni 】第六篇之native 中字符串和数组的操作

2022-06-26 22:01:00 华为云

继续JNI的知识点,今天看下字符串和数组的一些操作

这两个是比较特殊的存在

字符串操作

编码格式

Java默认使用Unicode编码,C/C++默认使用UTF编码

在本地代码中操作字符串的时候,JNI支持字符串在Unicode和UTF-8两种编码之间转换。

GetStringUTFChars能够把一个jstring指针(指向JVM内部的Unicode字符序列)转换成一个UTF-8格式的C字符串。

访问字符串

一般来说,在从JVM内部获取一个字符串之后。

JVM内部会分配一块新的内存,拷贝原来的字符串,以便本地代码访问和改动。

即然有内存分配。在使用完之后就应该释放。

ReleaseStringUTFChars()和GetStringUTFChars()必须成对出现,用来释放内存和引用,使对象可以被GC回收。

创建字符串

调用NewStringUTF函数会构建一个新的java.lang.String字符串对象。

JVM不能分配足够的内存,NewStringUTF会抛出一个OutOfMemoryError异常,并返回NULL

下面是一套连招

jstring NewStringUTF(JNIEnv *env, const char *bytes); jsize GetStringUTFLength(JNIEnv *env, jstring string);void ReleaseStringUTFChars(JNIEnv *env, jstring string,const char *utf);

两组函数 GetStringRegion 和 GetStringUTFRegion

void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);

上述两个函数是复制一段内容倒buff 数组中,避免了全部拷贝。

推荐使用GetStringUTFRegion

GetStringCritical和ReleaseStringCriticalconst jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);GetStringCritical得到的是一个指向JVM内部字符串的直接指针,获取这个直接指针后会导致暂停GC线程

这里传递的是jvm内部的指针,一定要小心,慎用

数组操作

数组的操作命名规则都是 operate + PrimitiveType + Array

先通过GetXXXArrayElements函数把简单类型的数组转化成本地类型的数组,

并返回其数组的指针,然后通过该指针来对拷贝数组进行处理。

对拷贝数组处理完后,通过ReleaseXXXArrayElements函数把修改后的拷贝数组的反射到java数组,

基本操作

//    获得数组长度jsize (GetArrayLength)(JNIEnv env, jarray array);//    创建数组jobjectArray NewObjectArray (JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);//    获取元素NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array, jboolean *isCopy);//    设置数据void SetObjectArrayElement(JNIEnv *env, jobjectArray array,jsize index, jobject value)//    释放元素void Release<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array, NativeType *elems, jint mode);

elems 参数是一个通过使用对应的GetPrimitiveTypeArrayElements() 函数由 array 导出的指针。

必要时,该函数将把对 elems 的修改复制回基本类型数组。mode参数将提供有关如何释放数组缓冲区的信息。

如果elems 不是 array 中数组元素的副本,mode将无效。

否则,mode 将具有下表所述的功能:

image.png

局部访问

//    将数组内容复制到 C 缓冲区内void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,jsize start, jsize len, NativeType *buf);//    将缓冲区内的内容复制到数组上void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,jsize start, jsize len, const NativeType *buf);

用来将基本类型数组某一区域复制到缓冲区中的一组函数/将基本类型数组的某一区域从缓冲区中复制回来的一组函数

直接访问

void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);

返回一个指定基础数据类型数组的直接指针,在这两个操作之间不能做任何阻塞的操作

来个例子

传递数组到C++

  // Java 传递 数组 到 C++ 进行数组求和    private native int intArraySum(int[] intArray, int size);

C++ 侧代码

JNIEXPORT jint JNICALLJava_com_demo_intArraySum(JNIEnv *env, jobject instance,                                                             jintArray intArray_, jint num) {    jint *intArray;    int sum = 0;    // 操作方法一:    // 如同 getUTFString 一样,会申请 native 内存    intArray = env->GetIntArrayElements(intArray_, NULL);    if (intArray == NULL) {        return 0;    }    // 得到数组的长度    int length = env->GetArrayLength(intArray_);    cout<<"array length is  "<<length;    for (int i = 0; i < length; ++i) {        sum += intArray[i];    }    cout<<"sum is  " <<sum);     // 操作方法二:    jint buf[num];    // 通过 GetIntArrayRegion 方法来获取数组内容    env->GetIntArrayRegion(intArray_, 0, num, buf);    sum = 0;    for (int i = 0; i < num; ++i) {        sum += buf[i];    }    cout<<"sum is  "<<sum;    // 使用完了别忘了释放内存    env->ReleaseIntArrayElements(intArray_, intArray, 0);    return sum;}

C++返回数组给Java

// 从 C++ 返回基本数据类型数组 private native int[] returnIntArray(int num);/** * 从 Native 返回 int 数组,主要调用 set<Type>ArrayRegion 来填充数据,其他数据类型类似操作 */extern "C"JNIEXPORT jintArray JNICALLJava_demo_returnIntArray(JNIEnv *env, jobject instance,                                                             jint num) {    jintArray intArray;    intArray = env->NewIntArray(num);     jint buf[num];    for (int i = 0; i < num; ++i) {        buf[i] = i * 2;    }     // 使用 setIntArrayRegion 来赋值    env->SetIntArrayRegion(intArray, 0, num, buf);    return intArray;}

总结

这篇主要写了字符串和数组的操作

基本上要记住的就是get ,set ,region 以及release 几个关键词

申请内存,释放内存,获取元素,操作元素



原网站

版权声明
本文为[华为云]所创,转载请带上原文链接,感谢
https://bbs.huaweicloud.com/blogs/361900