JNI字符串操做

在Java中,建立一個String對象的方式很是簡單,並且可使用String類的各類方法很方便的操做字符串。然而在JNI中,雖然jstring類表示Java的String類,可是jstring並無提供任何函數來操做字符串。html

編碼格式

對於一個字符串常量,例如"abc",在Java中是用一個String對象表示,而且表明UTF-16編碼格式的字符串(也就是雙字節編碼)。而在JNI中,是用一個char類型指針來表示,編碼格式卻爲modified UTF-8java

那麼什麼是modified UTF-8編碼格式呢?其實它與UTF-8格式很是像,可是有點小小的差異c++

  • 空字符(值爲0),在UTF-8中是用一個字節表示,然而在modified UTF-8中,是用兩個字節表示。
  • 對於一個字節,兩個字節,三個字節能夠表示的字符,這兩種編碼是同樣的
  • 對於須要用四個字節表示的字符,modified。 UTF-8使用的是兩個三字節來實現的。

若是想了解UTF-8modified UTF-8編碼格式,能夠參考文末連接。數組

JNI中對字符串的操做的函數,都有針對這兩個格式的版本。下面我對兩種編碼格式的字符串操做的函數作一個歸納性的講解。bash

UTF-16字符串函數

NewString

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

GetStringLength

jsize GetStringLength(JNIEnv *env, jstring string);
複製代碼

參數函數

  • jstring string: Java的String對象。

GetStringLength函數返回的字符串長度與Java的String返回的字符串的長度的是同樣的,例如String s = "中國";,這個Java字符串長度爲2,又例如String s = "China";,這個字符串長度爲5。ui

GetStringChars

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

ReleaseStringChars

void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
複製代碼

參數

  • jstring string: Java的String對象
  • jchar *chars: 指向由GetStringChars返回的Unicode編碼的字符數組

ReleaseStringChars函數並非本身去釋放本地字符串(若是發生拷貝),而是通知虛擬機本地代碼再也不訪問jchar *chars,而後虛擬機本身決定如何處理。

GetStringRegion

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中。

GetStringCritical & ReleaseStringCritical

const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
複製代碼

Get/ReleaseStringCritical函數與Get/ReleaseStringChars函數在使用和功能上是同樣的。也就是說,GetStringCritical函數可能返回一個指向原字符串的指針,或者返回一個指向源字符串的拷貝的指針,這取決與虛擬機實現。若是發生了拷貝,那麼就須要ReleaseStringCritial來通知虛擬機本地進行釋放操做。

modified UTF-8字符串函數

NewStringUTF

jstring NewStringUTF(JNIEnv *env, const char *bytes);
複製代碼

NewStringUTF的第二個參數const char *bytesmodified UTF-8編碼的字節數組。

modified UTF-8是JNI特有的格式,使用這種格式的字符串與虛擬機中使用的字符串同樣。

JNI使用modified UTF-8編碼來表示各類字符串類型,例以下面兩行代碼都是使用這種編碼的字符串

const char * bytes1 = "中國";
const char * bytes2 = "China";
複製代碼

因爲建立的字符串常量默認就是modified UTF-8編碼的,所以NewStringUTF也就是你們最經常使用的來獲取Java的String對象的函數。

GetStringUTFLength

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個字符長度。

GetStringUTFChars

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函數。

ReleaseStringUTFChars

void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
複製代碼

參數

  • jstring string: Java的String對象
  • const char *utf: 由GetStringUTFChars獲取。

ReleaseStringUTFChars函數只是通知虛擬機,本地代碼再也不訪問const char *utf,以後的處理動做取決與虛擬機。

GetStringUTFRegion

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編碼

docs.oracle.com/javase/7/do…

Unicode(UTF-8, UTF-16等)編碼

baike.baidu.com/item/Unicod…

相關文章
相關標籤/搜索