java是unicode编码,本地层则是utf-8编码
java String转化时,必须先decode转化成mirror::String,然后再转化成utf-8编码
static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy)
作用:将java String转化为c语言中的const char*
本质:
1. 将java String做decode操作 mirror::String* s = soa.Decode<mirror::String*>(java_string);
2. 取出mirror::String中的内容。const uint16_t* chars = s->GetValue();
3. unicode转码为utf-8: ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
看来本地层是用一个mirror::String对象来描述一个decode后的字符串
char* bytes = new char[byte_count + 1];
可以看出本地层自己申请了一片内存,然后将字符串拷贝进来,返回这个字符串的const char*
很明显这个字符串占有的内存和java中对应的字符串占用的不是同一片内存。
natvie层只是将它拷贝到另一块内存区域,然后返回const char*。
void nativePrint(JNIEnv *env, jobject thiz, jstring jstr) {
const char *nativeString = (*env)->GetStringUTFChars(env, jstr, 0);
(*env)->ReleaseStringUTFChars(env, jstr, nativeString);
}
static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
if (java_string == nullptr) {
return nullptr;
}
if (is_copy != nullptr) {
*is_copy = JNI_TRUE;
}
ScopedObjectAccess soa(env);
mirror::String* s = soa.Decode<mirror::String*>(java_string);
size_t byte_count = s->GetUtfLength();
char* bytes = new char[byte_count + 1];
CHECK(bytes != nullptr); // bionic aborts anyway.
const uint16_t* chars = s->GetValue();
ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
bytes[byte_count] = '\0';
return bytes;
}
-------------------------------------------------------------------------------------------------------------
static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length, char* buf)
GetStringUTFRegion和GetStringUTFChars类似,只是GetStringUTFRegion()在调用前需要先分配一块非const内存作为参数传进来。
而GetStringUTFChars()则是自己申请一块内存。调用完毕后返回的const char*,说明这块内存不让别人修改。
最后就是GetStringUTFRegion()copy到内存是局部变量,在栈上面,coder不用管理它。
GetStringUTFChars()调用完后copy到的内存是new出来的,虽然navie函数栈退出后,local ref table的内存是有限的,它会帮助释放这些内存。但是当我们不需要
使用这块内存时最好还是调用ReleaseStringUTFChars()去释放这块内存,以免local ref table内存不够用而溢出。
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
char outbuf[128];
int len = (*env)->GetStringLength(env, prompt);
(*env)->GetStringUTFRegion(env, prompt, 0, len, outbuf);
printf("%s", outbuf);
}
static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length, char* buf) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
ScopedObjectAccess soa(env);
mirror::String* s = soa.Decode<mirror::String*>(java_string);
if (start < 0 || length < 0 || start + length > s->GetLength()) {
ThrowSIOOBE(soa, start, length, s->GetLength());
} else {
CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
const jchar* chars = s->GetValue();
ConvertUtf16ToModifiedUtf8(buf, chars + start, length);
}
}