在Java中,创建一个		String
对象的方式非常简单,而且可以使用		String
类的各种方法很方便的操作字符串。然而在JNI中,虽然		jstring
类表示Java的		String
类,但是		jstring
并没有提供任何函数来操作字符串。	
对于一个字符串常量,例如		"abc"
,在Java中是用一个		String
对象表示,并且代表		UTF-16
编码格式的字符串(也就是双字节编码)。而在JNI中,是用一个		char
类型指针来表示,编码格式却为		modified UTF-8
。	
那么什么是		modified UTF-8
编码格式呢?其实它与		UTF-8
格式非常像,但是有点小小的差别	
UTF-8
中是用一个字节表示,然而在			modified UTF-8
中,是用两个字节表示。		modified。 UTF-8
使用的是两个三字节来实现的。		
如果想了解		UTF-8
和		modified UTF-8
编码格式,可以参考文末链接。	
JNI中对字符串的操作的函数,都有针对这两个格式的版本。下面我对两种编码格式的字符串操作的函数做一个概括性的讲解。
jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len); 复制代码
参数
jchar *unicodeChars
: 指向			Unicode
编码字符串的指针。		jsize len
: 字符串的长度。		
		NewString
使用		Unicode
编码的字符数组创建一个Java的		String
对象。	
使用		NewString
的关键就是必须使用		Unicode
编码的字符串,而这里的		Unicode
编码一般都是指		UTF-16
编码。但是如何获取这个		UTF-16
编码的字符串呢,这个超出本文讨论的范畴,但是在Android开发中,有一个		String16
的类,通过构造函数就可以把一个字符串常量转化为		UTF-16
编码的字符串。	
jsize GetStringLength(JNIEnv *env, jstring string); 复制代码
参数
jstring string
: Java的			String
对象。		
		GetStringLength
函数返回的字符串长度与Java的		String
返回的字符串的长度的是一样的,例如		String s = "中国";
,这个Java字符串长度为2,又例如		String s = "China";
,这个字符串长度为5。	
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());
}
复制代码