基本数据类型转换
在 Java 中传递的参数类型是 int,而在 JNI 中就成了 jint,这就涉及到 Java 到 JNI 的数据类型转换。
| Java 类型 | Native 类型 | 字节长度 |
|---|---|---|
| boolean | jboolean | 8位 |
| byte | jbyte | 8位 |
| char | jchar | 16位 |
| short | jshort | 16位 |
| int | jnit | 32位 |
| long | jlong | 64位 |
| float | jfloat | 32位 |
| double | jdouble | 64位 |
引用数据类型转换
除了基本数据类型之外,引用数据类型也有着一一对应。
| Java 类型 | Native 类型 |
|---|---|
| objects | jobject |
| java.lang.Class | jclass |
| java.lang.String | jstring |
| Object[] | jobjectArray |
| boolean[] | jbooleanArray |
| byte[] | jbyteArray |
| char[] | jcharArray |
| short[] | jshortArray |
| int[] | jintArray |
| long[] | jlongArray |
| float[] | jfloatArray |
| double[] | jdoubleArray |
| java.lang.Throwable | jthrowable |
除了 Java 中基本数据类型的数组、Class、String 和 Throwable 外,其余所有 Java 对象的数据类型在 JNI 中都用 jobject 表示。
String 字符串操作
对于基本数据类型的操作,比如 boolean、int、float 等都大同小异,无非是在原来的数据类型前面加了一个 j来表示 JNI 数据类型。
而对于 String 类型,必须要使用合适的 JNI 函数来将 jstring 转变成 C/C++ 字符串。
对于下面的 Native 方法,传入一个字符串,并要求返回一个字符串。
external fun stringFromJNI(): String
layout1Binding.tv1.setOnLongClickListener {
val str = strFromJNI("我是Java向C传递的参数")
layout1Binding.tv1.text = str
true
}
生成的对应的 C++ 代码如下:
extern "C"
JNIEXPORT jstring JNICALL
Java_com_znzy_myapplication_MainActivity_strFromJNI(JNIEnv *env, jobject thiz, jstring string) {
// 生成jstring
jstring returnValue = env->NewStringUTF("Hello Best");
// 把jstring类型的字符串转换为C风格的字符串,会额外申请内存
const char *str = env->GetStringUTFChars(string,0);
// 做检查判断
if (str == NULL){
return NULL;
}
// 实际操作
printf("%s",str);
LOGE("%s",str);
//释放申请的内存
env->ReleaseStringUTFChars(string,str);
return returnValue;
}
通过Java调用验证发现日志正常输出,页面正常显示

Java 层的字符串到了 JNI 就成了 jstring 类型的,但 jstring 指向的是 JVM 内部的一个字符串,它不是 C 风格的字符串 char*,所以不能像使用 C 风格字符串一样来使用 jstring 。
JNI 支持将 jstring 转换成 UTF 编码和 Unicode 编码两种。因为 Java 默认使用 Unicode 编码,而 C/C++ 默认使用 UTF 编码。
将 jstring 转换成 UTF 编码的字符串
- GetStringUTFChars(jstring string, jboolean* isCopy)
其中,jstring 类型参数就是我们需要转换的字符串,而 isCopy 参数的值为 JNI_TRUE 或者 JNI_FALSE ,代表是否返回 JVM 源字符串的一份拷贝。如果为JNI_TRUE 则返回拷贝,并且要为产生的字符串拷贝分配内存空间;如果为JNI_FALSE就直接返回了JVM 源字符串的指针,意味着可以通过指针修改源字符串的内容,但这就违反了 Java 中字符串不能修改的规定,在实际开发中,直接填 NULL就好了。
当调用完GetStringUTFChars 方法时别忘了做完全检查。因为 JVM 需要为产生的新字符串分配内存空间,如果分配失败就会返回 NULL,并且会抛出 OutOfMemoryError 异常,所以要对 GetStringUTFChars 结果进行判断。
当使用完 UTF 编码的字符串时,还不能忘了释放所申请的内存空间。调用 ReleaseStringUTFChars 方法进行释放。
除了将 jstring 转换为 C 风格字符串,JNI 还提供了将 C 风格字符串转换为 jstring 类型。
通过 NewStringUTF函数可以将 UTF 编码的 C 风格字符串转换为 jstring 类型,通过NewString 函数可以将 Unicode 编码的 C 风格字符串转换为 jstring 类型。这个 jstring 类型会自动转换成 Java 支持的 Unicode 编码格式。
除了 jstring 和 C 风格字符串的相互转换之外,JNI 还提供了其他的函数。
String 字符串函数操作总结
| JNI 函数 | 描述 |
|---|---|
| GetStringChars / ReleaseStringChars | 获得或释放一个指向 Unicode 编码的字符串的指针(指 C/C++ 字符串) |
| GetStringUTFChars / ReleaseStringUTFChars | 获得或释放一个指向 UTF-8 编码的字符串的指针(指 C/C++ 字符串) |
| GetStringLength | 返回 Unicode 编码的字符串的长度 |
| getStringUTFLength | 返回 UTF-8 编码的字符串的长度 |
| NewString | 将 Unicode 编码的 C/C++ 字符串转换为 Java 字符串 |
| NewStringUTF | 将 UTF-8 编码的 C/C++ 字符串转换为 Java 字符串 |
| GetStringCritical / ReleaseStringCritical | 获得或释放一个指向字符串内容的指针(指 Java 字符串) |
| GetStringRegion | 获取或者设置 Unicode 编码的字符串的指定范围的内容 |
| GetStringUTFRegion | 获取或者设置 UTF-8 编码的字符串的指定范围的内容 |
本文详细介绍了Java与JNI之间的数据类型转换,包括基本数据类型如boolean、int、float等如何转换为JNI对应的jboolean、jint、jfloat类型。同时,重点讨论了Java字符串在JNI中的处理,如如何使用GetStringUTFChars和ReleaseStringUTFChars进行UTF-8编码的转换和内存管理。此外,还总结了JNI中与字符串操作相关的函数,如NewStringUTF和NewString。
313

被折叠的 条评论
为什么被折叠?



