我以前是学Java的,对于C++只是明白很少的知识,所以看得越多,出现的问题也越多,我只有慢慢消化了
第四讲的第二部分:在C/C++本地代码中访问Java的String字符串对象
Java与C++中字符串的区别
- 在Java中,使用的字符串String 对象时Unicode(UTF-16)码,即每个字符不论是中文还是英文还是符号,一个字符总是占两个字节
- Java通过JNI接口可以将Java的字符串转换到C/C++的宽字符串(wchar_t*),或是传回一个UTF-8的字符串(char*)到C/C++.
- C/C++可以通过一个看字符串或是一个UTF-8编码的字符串来创建一个Java端的String对象
JNI中操作字符串相关函数
函数作用是取得某个jstring对象相关的Java字符串,介绍了三种类型的字符串操作函数
1、GetStringChars 与 GetStringUTFChars
- GetStringChars 取得UTF-16编码的宽字符串(jchar*)
- GetStringUTFChars 取得UTF-8编码的字符串(char*)
const jchar *GetStringChars(jstring str, jboolean *isCopy) {
return functions->GetStringChars(this,str,isCopy);
}
const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
return functions->GetStringUTFChars(this,str,isCopy);
}
void ReleaseStringChars(jstring str, const jchar *chars) {
functions->ReleaseStringChars(this,str,chars);
}
void ReleaseStringUTFChars(jstring str, const char* chars) {
functions->ReleaseStringUTFChars(this,str,chars);
}
1 )、参数
- 第一个参数传入一个指向Java中的String对象的jstring变量.
- 第二个参数传入jboolean 指针,标示是否对Java的String对象进行了Copy。也就是会给该指针指向的内存传入JNI_TRUE 或JNI_FALSE 标示是否进行了拷贝、NULL表示不关心是否拷贝,就不想内存赋值
2 )、这两个函数可以两种方式进行字符串的Copy
- 开辟新内存,Java中的String拷贝到新内存中,最后返回指向这个内存地址的指针.
- 直接返回指向Java中String的内存指针,此时 千万不能改变这个内存的内容,这会破坏String在Java中始终是常量的原则 (我们都知道Java中String为不可变对象,一旦被创建,就不能修改它的值.需要修改则需要重新创建对象 )
3 )、释放拷贝的内存
在取得字符串后,当已经不再之用,需要通过ReleaseStringChars、ReleaseStringUTFChars来释放拷贝所用的内存或释放Java的String对象的引用.(上面代码中)
- 参数一:指定jstring变量—>本地要释放的字符串来源
- 参数二:释放本地字符串
2、GetStringCritical 与 ReleaseStringCritical
为了增加直接传回Java字符串的指针的可能性(不是拷贝)JDK1.2 之后增加GetStringCritical、ReleaseStringCritical
const jchar * GetStringCritical(jstring string, jboolean *isCopy) {
return functions->GetStringCritical(this,string,isCopy);
}
void ReleaseStringCritical(jstring string, const jchar *cstring) {
functions->ReleaseStringCritical(this,string,cstring);
}
- 这两个函数之间是一个关键区,在这个关键区中不能调用JNI的其它函数或可能造成当前线程中断、等待的任何本地代码 , 否则将造成关键区代码执行期间垃圾回收器停止运作,任何触发垃圾回收器的线程也将暂停,其它触发垃圾回收器的线程不能前进,直到当前线程结束来激活垃圾回收器
- 关键区中不能出现中断操作,不能在 JVM 中分配新对象,否则造成 JVM 死锁.
- 虽然增加了直接传回Java字符串指针的可能性,不过还是需要根据实际情况传回拷贝过的字符串,如 Java 字符串是UTF-16 ,要想转成UTF-8编码还是需要进行拷贝,所以也就没有GetStringUTFCritical 这个函数
3、GetStringRegion 与 GetStringUTFRegion
Java 1.2中新增函数,可以实现把Java字符串直接拷贝到C++的字符串数组中,在调用这个函数之前必须有一个C++分配出来的字符串,然后通过这个函数进行字符串的拷贝
优点:函数拷贝不需要分配内存,Java中的String内容的拷贝的开销可以忽略,所以不会造成OutOFMemoryError异常.
void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {
functions->GetStringRegion(this,str,start,len,buf);
}
void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {
functions->GetStringUTFRegion(this,str,start,len,buf);
}
将指向Java字符串的 jstring 以相应编码 截取之后 传入 C++分配出来存储字符串的空间buf