JNI 字符串
- 创建 jsting 字符串(C、C++ 的字符串返回给 java)
jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);
jstring NewStringUTF(JNIEnv *env, const char *bytes);
这个新创建的字符串会自动转换成Java支持的Unicode编码。如果JVM不能为构造java.lang.String分配足够的内存,NewStringUTF会抛出一个OutOfMemoryError异常,并返回NULL
- 获取 jsting 长度(由于UTF-8编码的字符串以'\0'结尾,而Unicode字符串不是)
jsize GetStringLength(JNIEnv *env, jstring string);
jsize GetStringUTFLength(JNIEnv *env, jstring string);
- 从 jstring 中获取 char * (获取 java 传递给 C、C++ 的字符串)
const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
const char* GetStringUTFChars(jstring string, jboolean* isCopy)
isCopy:取值JNI_TRUE和JNI_FALSE,如果值为JNI_TRUE,表示返回JVM内部源字符串的一份拷贝,并为新产生的字符串分配内存空间。如果值为JNI_FALSE,表示返回JVM内部源字符串的指针,意味着可以通过指针修改源字符串的内容,不推荐这么做,因为这样做就打破了Java字符串不能修改的规定。但我们在开发当中,并不关心这个值是多少,通常情况下这个参数填nullptr即可
const char* s = env->GetStringUTFChars(sFromJava, nullptr);
不管有没有复制一份,使用完了都需要 release。(从 java 中 get 到的类和对象都需要 release)
- 从字符串中的指定位置复制指定长度的字符到字符数组中
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
GetStringUTFRegion这个函数会做越界检查,如果检查发现越界了,会抛出StringIndexOutOfBoundsException异常,这个方法与GetStringUTFChars比较相似,不同的是,GetStringUTFRegion内部不分配内存,不会抛出内存溢出异常。
GetStringUTFRegion和GetStringRegion这两个函数由于内部没有分配内存,所以JNI没有提供ReleaseStringUTFRegion和ReleaseStringRegion这样的函数。
字符串总结
- 对于小字符串来说,GetStringRegion和GetStringUTFRegion这两对函数是最佳选择,因为缓冲区可以被编译器提前分配,而且永远不会产生内存溢出的异常。当你需要处理一个字符串的一部分时,使用这对函数也是不错。因为它们提供了一个开始索引和子字符串的长度值。另外,复制少量字符串的消耗 也是非常小的。
- 使用GetStringCritical和ReleaseStringCritical这对函数时,必须非常小心。一定要确保在持有一个由 GetStringCritical 获取到的指针时,本地代码不会在 JVM 内部分配新对象,或者做任何其它可能导致系统死锁的阻塞性调用
- 获取Unicode字符串和长度,使用GetStringChars和GetStringLength函数
- 获取UTF-8字符串的长度,使用GetStringUTFLength函数
- 创建Unicode字符串,使用NewStringUTF函数
- 从Java字符串转换成C/C++字符串,使用GetStringUTFChars函数
- 通过GetStringUTFChars、GetStringChars、GetStringCritical获取字符串,这些函数内部会分配内存,必须调用相对应的ReleaseXXXX函数释放内存