在Java中,建立一个String
对象的方式很是简单,并且可使用String
类的各类方法很方便的操做字符串。然而在JNI中,虽然jstring
类表示Java的String
类,可是jstring
并无提供任何函数来操做字符串。html
对于一个字符串常量,例如"abc"
,在Java中是用一个String
对象表示,而且表明UTF-16
编码格式的字符串(也就是双字节编码)。而在JNI中,是用一个char
类型指针来表示,编码格式却为modified UTF-8
。java
那么什么是modified UTF-8
编码格式呢?其实它与UTF-8
格式很是像,可是有点小小的差异c++
UTF-8
中是用一个字节表示,然而在modified UTF-8
中,是用两个字节表示。modified。 UTF-8
使用的是两个三字节来实现的。若是想了解
UTF-8
和modified UTF-8
编码格式,能够参考文末连接。数组
JNI中对字符串的操做的函数,都有针对这两个格式的版本。下面我对两种编码格式的字符串操做的函数作一个归纳性的讲解。bash
jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);
复制代码
参数oracle
jchar *unicodeChars
: 指向Unicode
编码字符串的指针。jsize len
: 字符串的长度。NewString
使用Unicode
编码的字符数组建立一个Java的String
对象。app
使用NewString
的关键就是必须使用Unicode
编码的字符串,而这里的Unicode
编码通常都是指UTF-16
编码。可是如何获取这个UTF-16
编码的字符串呢,这个超出本文讨论的范畴,可是在Android开发中,有一个String16
的类,经过构造函数就能够把一个字符串常量转化为UTF-16
编码的字符串。ide
jsize GetStringLength(JNIEnv *env, jstring string);
复制代码
参数函数
jstring string
: Java的String
对象。GetStringLength
函数返回的字符串长度与Java的String
返回的字符串的长度的是同样的,例如String s = "中国";
,这个Java字符串长度为2,又例如String s = "China";
,这个字符串长度为5。ui
const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
复制代码
参数
jstring string
: Java的String
对象jboolean * isCopy
: 若是isCopy
不为NULL
,而且函数生成的是字符串的拷贝,那么*isCopy
的值为JNI_TRUE
,若是没有生成拷贝,那么*isCopy
值为JNI_FALSE
GetStringChars
返回一个指向Unicode
编码的字符数组的指针(指针可能为NULL
)。这个指针可能指向原字符串的数组,也可能指向拷贝的字符数组,取决与虚拟机的实现。若是是生成拷贝,就须要释放本地字符串,须要使用ReleaseStringChars
。
void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
复制代码
参数
jstring string
: Java的String
对象jchar *chars
: 指向由GetStringChars
返回的Unicode
编码的字符数组ReleaseStringChars
函数并非本身去释放本地字符串(若是发生拷贝),而是通知虚拟机本地代码再也不访问jchar *chars
,而后虚拟机本身决定如何处理。
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
复制代码
参数
jstring str
: Java的String
对象jsize start
: 拷贝的开始位置jsize len
: 拷贝的长度jchar *buf
: 拷贝的目标缓冲区GetStringRegion
函数从start
开始,拷贝len
长度的Unicode
字符到buf
中。
const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
复制代码
Get/ReleaseStringCritical
函数与Get/ReleaseStringChars
函数在使用和功能上是同样的。也就是说,GetStringCritical
函数可能返回一个指向原字符串的指针,或者返回一个指向源字符串的拷贝的指针,这取决与虚拟机实现。若是发生了拷贝,那么就须要ReleaseStringCritial
来通知虚拟机本地进行释放操做。
jstring NewStringUTF(JNIEnv *env, const char *bytes);
复制代码
NewStringUTF
的第二个参数const char *bytes
是modified UTF-8
编码的字节数组。
modified UTF-8
是JNI特有的格式,使用这种格式的字符串与虚拟机中使用的字符串同样。
JNI使用modified UTF-8
编码来表示各类字符串类型,例以下面两行代码都是使用这种编码的字符串
const char * bytes1 = "中国";
const char * bytes2 = "China";
复制代码
因为建立的字符串常量默认就是modified UTF-8
编码的,所以NewStringUTF
也就是你们最经常使用的来获取Java的String
对象的函数。
jsize GetStringUTFLength(JNIEnv *env, jstring string);
复制代码
参数
jstring string
: Java的String
对象GetStringUTFLength
函数返回一个modified UTF-8
编码格式字符串的字节长度。
注意,GetStringUTFLength
返回的是字节长度,而GetStringLength
返回的字符长度。一个是强调字节,一个是强调字符,这是有却别的。例如对于一个Java的字符串String s = "中国"
,GetStringUTFLength
返回的值为6,表明6个字节长度,而GetStringLength
返回的值为2,表明2个字符长度。
const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
复制代码
参数
jstring string
: Java的String对象jboolean * isCopy
: 若是isCopy
不为NULL
,而且若是函数对原字符串进行了拷贝,那么*isCopy
的值为JNI_TRUE
,若是没有发生拷贝,那么*isCopy
的值为JNI_FALSE
。GetStringUTFChars
函数返回一个指向modified UTF-8
编码的字节数组指针。
从参数isCopy
能够看出,GetStringUTFChars
函数返回的指向字节数组的指针,可能指向远字符串,也可能指向拷贝的字符串。若是一旦发生了拷贝,那么在不须要这个拷贝的时候,就须要进行释放,能够调用ReleaseStringUTFChars
函数。
void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
复制代码
参数
jstring string
: Java的String
对象const char *utf
: 由GetStringUTFChars
获取。ReleaseStringUTFChars
函数只是通知虚拟机,本地代码再也不访问const char *utf
,以后的处理动做取决与虚拟机。
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start,
jsize len, char *buf);
复制代码
GetStringUTFRegion
函数与GetStringRegion
函数的参数是同样,不一样的是GetStringUTFRegion
函数会把拷贝到缓冲区的字符从Unicode
转化为modified UTF-8
格式。
通常状况下,咱们都选择使用JNI默认的modified UTF-8
编码字符串,由于很方便,不须要转换编码。而若是必定要使用UTF-16
编码字符串,那么就须要进行转换。
那么如何在JNI层更好的处理字符串呢?若是使用的是C++开发JNI,那么能够在JNI层使用string
类来操做字符串,而若是使用C语言,那么不得不使用字符指针一步一步来处理。
例如,一个Java类中有一个native
方法
public class Hello {
native string getHelloFromJNI(String name);
}
复制代码
在JNI层对应的实现为
static jstring getHello(JNIEnv *env, jobject thiz, jstring name) {
// 从Java的String对象转换为本地表示
const char *c_name = env->GetStringUTFChars(name, NULL);
// 使用C++的string进行字符串拼接
string str("Hello, ");
str.append(c_name);
str.append("!");
env->ReleaseStringUTFChars(name, c_name);
// 建立Java的String对象并返回
return env->NewStringUTF(str.c_str());
}
复制代码
modified UTF-8编码
Unicode(UTF-8, UTF-16等)编码