在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等)編碼