文章目录
I . C/C++ 中的 Java 字符串数组类型
II . 获取字符串数组长度
III . 获取字符串数组元素
IV . 类型强转 ( jobject -> jstring )
V . 字符串转换 ( jstring -> char* )
VI . 字符串释放
VII . 部分代码示例
I . C/C++ 中的 Java 字符串数组类型
JNI 中 C/C++ 代码里的 Java 字符串数组类型 : jobjectArray ;
① JNI 类型现状 : 在 JNI 中没有定义 Java 字符串数组类型 , 只定义了 Java 字符串类型 jstring ;
② Object 对应 jobject : 在 C/C++ 环境中 jobject 类型对应 Java 中的 Object 类型 , Java 中字符串也是 Object 类型的 ;
③ 字符串数组类型 : 因此在 C/C++ 环境中使用 对象数组 jobjectArray 来当做 字符串数组类型 ;
II . 获取字符串数组长度
1 . 前提条件 : Java 层传入参数 jobjectArray stringArray , 该参数对应 Java 代码中的 String[] stringArray 参数 ;
下面的 GetArrayLength 方法的 stringArray 参数 , 就是 jobjectArray 类型的 ;
2 . 获取字符串数组长度 代码示例 : 其中返回值 jsize 是 int 类型的别名 ;
jsize stringArrayLength = env->GetArrayLength(stringArray);
GetArrayLength 方法详细解析参考如下内容 :
GetArrayLength 方法解析 ( 获取 jarray 数组长度 )
III . 获取字符串数组元素
C/C++ 代码中获取指定索引的 Java 字符串数组类型的元素 ;
1 . 调用方法 : 调用 JNIEnv * env 的 GetObjectArrayElement 方法 , 可以获取指定索引的 jobject 引用类型变量 ;
2 . 方法原型 :
struct _JNIEnv { /* _JNIEnv 结构体中封装了 JNINativeInterface 结构体指针 */ const struct JNINativeInterface* functions; ... // 最终 调用的 还是 JNINativeInterface 结构体中封装的 GetObjectArrayElement方法 jobject GetObjectArrayElement(jobjectArray array, jsize index) { return functions->GetObjectArrayElement(this, array, index); } ... }
3 . GetObjectArrayElement 参数说明 :
① jobjectArray array 参数 : 由 Java 层传入的 Java 对象数组 ;
② jsize index 参数 : 要获取的数组元素的索引值 ;
4 . 获取对象数组指定元素代码示例 :
其中的参数 stringArray 是 jobjectArray 类型的 , 由 JNI 方法传入 ;
其中的参数 i 是 int 类型的 , 是要获取的元素的索引值 , 从 0 开始计数 ;
jobject string_object = env->GetObjectArrayElement(stringArray, i);
IV . 类型强转 ( jobject -> jstring )
将 jobject 转为 jstring 类型 : string_object 是 jobject 类型变量 ;
// 2.2 将 jobject 类型强转成 jstring 类型 , 这两个都代表了 Java 的数据类型 jstring string_java = static_cast<jstring>(string_object);
详细内容参考下面博客 :
【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 )
V . 字符串转换 ( jstring -> char* )
1 . GetStringUTFChars 方法 : 将 jstring 类型字符串 ( Java 中的字符串 ) 转为 char* 类型字符串 ( C/C++ 中的字符串 ) ;
2 . 函数原型 : jstring string 参数是 Java 通过 JNI 传入的 , 代表 Java 字符串 ;
struct _JNIEnv { /* _JNIEnv 结构体中封装了 JNINativeInterface 结构体指针 */ const struct JNINativeInterface* functions; ... // 最终 调用的 还是 JNINativeInterface 结构体中封装的 GetStringUTFChars 方法 const char* GetStringUTFChars(jstring string, jboolean* isCopy) { return functions->GetStringUTFChars(this, string, isCopy); } ... }
3 . jboolean* isCopy 参数 : 该参数用于指定将 jintArray 类型的变量 , 转为 jint * 指针类型的变量 , 新的指针变量的生成方式 ;
① 将 该参数设置成指向 JNI_TRUE 的指针 : 将 int 数组数据拷贝到一个新的内存空间中 , 并将该内存空间首地址返回 ;
② 将 该参数设置成指向 JNI_FALSE 的指针 : 直接使用 java 中的 int 数组地址 , 返回 java 中的 int 数组的首地址 ;
③ 将 该参数设置成 NULL ( 推荐 ) : 表示不关心如何实现 , 让系统自动选择指针生成方式 , 一般情况下都不关心该生成方式 ;
④ jboolean 类型取值 : jboolean 的取值只能是 0 和 1 , 也可以使用 JNI_FALSE 和 JNI_TRUE 宏定义 ;
#define JNI_FALSE 0 #define JNI_TRUE 1
4 . jstring 字符串转换 为 char* 字符串示例 :
const char *string_c = env->GetStringUTFChars(string_java, JNI_FALSE);
VI . 字符串释放
1 . ReleaseStringUTFChars 方法 : 将 Java 字符串 和 C/C++ 字符串都释放 ;
2 . 函数原型 :
jstring string 参数是 Java 通过 JNI 传入的 , 代表 Java 字符串 ; const char* utf 参数是通过 GetStringUTFChars 方法将上面的 Java 字符串转成的 C/C++ 字符串 ; struct _JNIEnv { /* _JNIEnv 结构体中封装了 JNINativeInterface 结构体指针 */ const struct JNINativeInterface* functions; ... // 最终 调用的 还是 JNINativeInterface 结构体中封装的 ReleaseStringUTFChars 方法 void ReleaseStringUTFChars(jstring string, const char* utf) { functions->ReleaseStringUTFChars(this, string, utf); } ... }
VII . 部分代码示例
部分代码示例 :
#include <jni.h> #include <string> //导入日志库 #include <android/log.h> //定义日志宏 , 其中的 __VA_ARGS__ 表示可变参数 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"JNI",__VA_ARGS__); ... extern "C" JNIEXPORT void JNICALL Java_kim_hsl_jni_MainActivity_jniArrayTest(JNIEnv *env, jobject instance, jintArray intArray_, jobjectArray stringArray) { ... // II . 引用类型数组操作 ( 获取字符串数组 ) // 1 . 获取字符串数组长度 jsize stringArrayLength = env->GetArrayLength(stringArray); // 2 . 遍历字符串数组 for(int i = 0; i < stringArrayLength; i ++) { /* 2.1 获取 jobject 数组中第 i 个元素 注意 : 获取的是 jobject 类型变量 函数原型 : jobject GetObjectArrayElement(jobjectArray array, jsize index) jobjectArray array 参数 : 是 Java 层传入的 Java 对象数组 参数 , 即 Native 层的调用函数的参数 jsize index 参数 : 对象元素的索引值 , 取值范围 0 ~ stringArrayLength - 1 返回值 : 返回的是 jobject 类型的变量 */ jobject string_object = env->GetObjectArrayElement(stringArray, i); // 2.2 将 jobject 类型强转成 jstring 类型 , 这两个都代表了 Java 的数据类型 jstring string_java = static_cast<jstring>(string_object); /* 2.3 将 jstring 类型转为 char* 类型 jstring 类型简介 : class _jobject {}; class _jstring : public _jobject {}; typedef _jstring* jstring; 由上面可见 , jstring 只是 继承了 _jobject 类 , 没有任何实现 , 是一个空类 因此需要借助 C/C++ 方法 将 java 类型的 jstring 字符串 其转为 C/C++ 类型的 char* 类型字符串 转换函数原型 : void ReleaseStringUTFChars(jstring string, const char* utf) */ const char *string_c = env->GetStringUTFChars(string_java, 0); // 2.4 打印 转换后的 字符串值 __android_log_print(ANDROID_LOG_INFO, "JNI_TAG", "打印字符串数组元素 : %d . %s", i, string_c); // 2.5 释放 char* 字符串 env->ReleaseStringUTFChars(string_java, string_c); } }
代码执行结果 :
01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印 int 数组元素 : 0 . 1 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印 int 数组元素 : 1 . 2 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印 int 数组元素 : 2 . 666 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印 int 数组元素 : 3 . 888 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印 int 数组元素 : 4 . 95555 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印字符串数组元素 : 0 . Hello 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印字符串数组元素 : 1 . World 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: 打印字符串数组元素 : 2 . Hanshuliang 01-12 19:45:59.634 11885-11885/kim.hsl.jni I/JNI_TAG: Java 层 jniArrayTest 执行完毕后 , int[] intArray 数组内容 : [8888, 8888, 8888, 8888, 8888]
限于篇幅就不再贴完整代码了 , 去下载博客资源有全套的 JNI 文档教程 , 及博客源码