JNI把Java中的对象当做一个C指针传到本地方法中,这个指针指向JVM中的内部数据结构。使用这种指针的目的是不希望JNI用户了解JVM内部数据结构。对于该类指针所指结构的操作都要通过JNI方法进行。
在学习Java与C/C++字符串传递之前先明确几个关于字符编码的基本概念:
a) Java内部使用16bit的Unicode编码(utf-16)来表示字符串;
b) Jni内部使用utf-8编码来表示字符串
c) C/C++使用的是原始数据,ascii是一个字节,中文一般是GB2312编码
1、 Java字符串——>C++字符串
这种情况下java中的字符串是utf-16编码的,C++得到的输入时jstring类型。这时可以利用jni提供的两种函数将jstring转成C++字符串。一个是GetStringUTFChars,这个函数得到一个utf-8编码的字符串;另一个是GetStringChars,这个将得到utf-16编码的字符串。
a) 函数原型:
const jchar* GetStringChars ( jstring str , jboolean * copied)
const char* GetStringUTFChars(jstring str , jboolean * copied )
第一个参数传入一个指向java中string对象的jstring变量;第二个参数是一个jboolean类型的指针,用来标示是否对java的String对象进行了拷贝。它有三种取值:JNI_TRUE , JNI_FALSE , NULL。
取JNI_TRUE时函数执行的动作为:开辟新内存,然后把Java中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。
取JNI_FALSE时函数执行的动作为:直接返回指向Java中String的内存的指针。这时候千万不要改变这个内存的内容,这将破坏String在Java中始终是常量这个原则。
取NULL则表示不关心是否拷贝字符串。
使用这两个函数取得的字串,在不使用的时候要调用ReleaseStringChars/ReleaseStringUTFChars来释放拷贝的内存,或是释放对Java的String对象的引用。
b) 函数原型:
ReleaseStringChars ( jstring jstr , const jchar* str)
ReleaseStringUTFChars ( jstringjstr , const char* str)
第一个参数指向一个jstring变量,即要释放的本地字符串的来源;第二个参数就是要释放的本地字符串
c) 为了增加直接传回指向java字符串的指针的可能性(而不是拷贝),JDK 1.2出来了新的函数GetStringCritical/ReleaseStringCritical。
函数原型
const jchar* GetStringCritical ( jstring str , jboolean*copied )
void ReleaseStringCritical( jstring jstr , constjchar* str )
在这两个函数之间是一个关键区,在关键去绝对不能呼叫JNI的其他函数和会造成当前线程中断或是会让当前线程等待的任何本地代码,否则将造成关键区代码执行期间垃圾回收器停止运作,任何触发垃圾回收器的线程也会暂停。
另外没有GetStringUTFCritical这样的函数。因为java字符串转成utf-8编码的字符串始终需要进行一次拷贝,所以没有这样的函数。
d) GetStringRegion/GetStringUTFRegion这两个函数是向准备好的缓冲区内赋值,直接把java字符串的内容拷贝到C/C++的字符数组中。这是因为C/C++中分配内存开销相对较小,而且java中的String内容拷贝的开销可以忽略。更好的一点是此函数不分配内存,不会抛出OutofMemoryError异常。
函数原型:
void GetStringUTFRegion( jstring str , jsize start , jsize len , char* buffer )
void GetStringRegion ( jstring str , jsize start , jsize len , jchar* buffer)
start代表拷贝开始的索引值,len表示拷贝的长度,buffer指向C/C++分配出来的用来存储拷贝字符串的空间。
e) 其他函数
GetStringLength/GetStringUTFLength:取得字符串的长度
函数原型:
jsize GetStingLength ( jstring str )
jsize GetStringUTFLength ( jstring str )
前者是Unicode编码的长度,后者是uft-8编码的长度。
2、 C++字符串——>Java字符串
C/C++首先应该负责把这个字符串变成utf-8或者utf-16格式,然后通过NewString或者NewStingUTF来把它封装成jstring利用函数SetObjectField返回给java。
函数原型:
Jstring NewString( const jchar* str , jsize len )
Jstring NewStringUTF(const char* str )
第一个函数中的参数str代表了宽字符串,len表示宽字符串的长度;第二个函数中的str代表以utf-8编码的字符串,这里不需要参数len是因为utf-8编码的字符串以’\0’结尾,所以不需要传长度。
这篇博客详细介绍了JNI中Java字符串与C++字符串之间的转换操作,包括GetStringUTFChars、GetStringChars、ReleaseStringChars等函数的使用,以及如何从C++创建Java字符串。同时,还讨论了不同编码(utf-16、utf-8)在JNI中的应用。
1153

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



