[Android應用開發]-(15)JNI----基礎資料型別 (Elementary Data Type)

來源:互聯網
上載者:User

這篇拙文將通過執行個體的方式來簡易學習JNI的資料類型。任何語言都有其基本的資料類型,要深入瞭解,必須要瞭解最基礎的東西,在JNI中,我們會問:Java語言中的資料類型是如何映射到C/C++本地語言中的呢?

目錄:

   1. 一個簡單的執行個體分析

    2. Java與JNI資料類型的映射

    3. 字串的處理

    4. 數組的處理

 


1. 一個簡單的執行個體分析編程中,向函數傳參和函數傳回值是很普遍的事情,這裡就通過幾個執行個體介紹這些技術。先通過一個簡單的執行個體來入門吧。這裡擴充HelloWorld.java,先列印一段字串,然後等待使用者輸入,看代碼:(這裡我只列出C的代碼)

[cpp]
<SPAN style="FONT-SIZE: 16px">  JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *, jobject, jstring);//(這串代碼怎麼來的,請看【Android應用開發】-(14)JNI----經典執行個體分析 )</SPAN> 

  JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *, jobject, jstring);//(這串代碼怎麼來的,請看【Android應用開發】-(14)JNI----經典執行個體分析 )
我們看getLine這個函數接收三個參數JNIEnv,jobject,jstring。其中JNIEnv包括JNI的函數表,如:

jobject的意義取決於該方法是靜態還是執行個體方法,當本地方法作為一個方法時,jobject相當於對象本身,即this。當本地方法作為一個靜態方法時,指向所在類。在本執行個體中,getline是一個本地執行個體方法實現,所以jobject指向對象本身。

 

2. 類型的映射

按資料類型來說,java中有兩種資料類型,基本的資料類型(int float,char),另一種是參考型別(執行個體、數組)。在本地方法(native 聲明的方法)中聲明的參數類型,在JNI中都有對應的類型。

Java與JNI基本類型的映射很直接,請看下錶:

Java                                                
 Native(jni.h)                                   
 
boolean
 jboolean
 
byte
 jbyte
 
char
 jchar
 
short
 jshort
 
Int
 jint
 
long
 jlong
 
Float
 jfloat
 
double
 jdouble
 


除了這些類型之外還定義了jstring,jclass,jobjectArray等結構。他們都繼承自jobject.


相比基本類型,物件類型的傳遞要複雜很多。Java層的對象對象以(opaque references)指標的形勢傳遞到JNI層。opaque references是C的指標類型,它指向JavaVM內部資料結構。使用這種指標的目的是:不希望JNI使用者瞭解JAVAVM內部資料結構。對opaque references所指結構的操作,都要通過JNI方法進行。比如,”java.lang.String”對象,JNI層對於的類型為jstring,對該opaque references的操作要通過JNIEnv->GetStringUTFChars進行。這裡需要注意的是:編程的過程中一定要按照原則編程,千萬不要為了效率或者容易渠道某個值而繞過JNI,直接操作opaque references。

 

3. 字串處理

1) 執行個體

現在我們回到執行個體中,看如何處理從java傳過去的String類型,請看下面代碼?

[cpp]
JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){ 
    Printf(“%s”,prompt); 

JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
 Printf(“%s”,prompt);
}
很抱歉,出錯了:incorrect use of jstring as a char* pointer。

這裡需要使用對於JNI函數把jstring裝好為C/C++字串。JNI支援Unicode/UTF-8字元編碼互轉。Unicode 以16-bits值編碼;UTF-8是一種以位元組為單位變長格式的字元編碼,並與7-bits ASCII碼相容。UTF-8字串與C字串一樣,以NULL('\0')做結束符, 當UTF-8包含非ASCII 碼字元時,以'\0'做結束符的規則不變。7-bit ASCII字元的取值範圍在 1-127之間,這些 字元的範圍與UTF-8中相同。當最高位被設定時,表示多位元組編碼。如下,調用GetStringUTFChars,把一個Unicode字串轉成UTF-8格式字串,如果你確定字串只包含7-bit ASCII字元。這個字串可以使用C庫中的相關函數,如printf.

[cpp]
Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){ 
char buf[128];  
    const jbyte *str;  
    str =  (*env)->GetStringUTFChars(env, prompt, NULL);  
    if  (str == NULL) {  
      return NULL; /* OutOfMemoryError already thrown */  
    }  
    printf("%s , str);  
     (*env)->ReleaseStringUTFChars(env, prompt, str);  
    /* We assume here that the user does not type more than 127 characters */  
    scanf("%127s , buf);  
  return  (*env)->NewStringUTF(env, buf); 
 } 

Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
char buf[128];
    const jbyte *str;
    str =  (*env)->GetStringUTFChars(env, prompt, NULL);
    if  (str == NULL) {
      return NULL; /* OutOfMemoryError already thrown */
    }
    printf("%s , str);
     (*env)->ReleaseStringUTFChars(env, prompt, str);
    /* We assume here that the user does not type more than 127 characters */
    scanf("%127s , buf);
  return  (*env)->NewStringUTF(env, buf);
 }

這裡一定要檢測GetStringUTFChars的傳回值,因為調用該函數會有記憶體配置操作。失敗有該函數返回NULL,並拋出OutOfMemoryError異常。發生異常不會改變代碼的執行軌跡,所以當返回Null時要及時處理異常。

1) 釋放GetStringUTFChars調用時的記憶體使用量。ReleaseStringUTFChars

2) 構造新的字串使用JNIEnv->NewStringUTF,同樣的,如果沒有足夠的記憶體也會拋出OutOfMemoryError異常。

3) 其他字串操作方法

GetStringChars是有Java 內部Unicode到本地UTF-8的轉換函式,可以調用 GetStringLength,獲得以Unicode編碼的字串長度。也可以使用strlen計算 GetStringUTFChars的傳回值,得到字串長度。

const jchar * GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy);

具體的使用請參考JNI詳解16-20頁

4. 數組的操作

Java部分代碼很簡單,不貼出來了。我們直接看C代碼。

[cpp]
JNIEXPORT jint JNICALL Java_org_winplus_basetype_IntArray_sumArray(JNIEnv *env, 
        jobject obj, jintArray arr) { 
    // 我們不能直接這樣操作。  
    /* This program is illegal! */ 
    /*int i, sum = 0;
     for (i = 0; i < 10; i++) {
     sum += arr[i];
     }*/ 
 
    //////////////////////////////////範例程式碼1///////////////////////////  
 
//  jint buf[10];  
//  jint i, sum = 0;  
//  (*env)->GetIntArrayRegion(env, arr, 0, 10, buf);  
//  for (i = 0; i < 10; i++) {  
//      sum += buf[i];  
//  }  
//  return sum;  
 
    ///////////////////////////////////範例程式碼2///////////////////////////  
    jint *carr; 
    jint j, sum1 = 0; 
    carr = (*env)->GetIntArrayElements(env, arr, NULL); 
    if (carr == NULL) { 
        return 0; /* exception occurred */ 
    } 
    for (j = 0; j < 10; j++) { 
        sum1 += carr[j]; 
    } 
    (*env)->ReleaseIntArrayElements(env, arr, carr, 0); 
    return sum1; 

JNIEXPORT jint JNICALL Java_org_winplus_basetype_IntArray_sumArray(JNIEnv *env,
  jobject obj, jintArray arr) {
 // 我們不能直接這樣操作。
 /* This program is illegal! */
 /*int i, sum = 0;
  for (i = 0; i < 10; i++) {
  sum += arr[i];
  }*/

 //////////////////////////////////範例程式碼1///////////////////////////

// jint buf[10];
// jint i, sum = 0;
// (*env)->GetIntArrayRegion(env, arr, 0, 10, buf);
// for (i = 0; i < 10; i++) {
//  sum += buf[i];
// }
// return sum;

 ///////////////////////////////////範例程式碼2///////////////////////////
 jint *carr;
 jint j, sum1 = 0;
 carr = (*env)->GetIntArrayElements(env, arr, NULL);
 if (carr == NULL) {
  return 0; /* exception occurred */
 }
 for (j = 0; j < 10; j++) {
  sum1 += carr[j];
 }
 (*env)->ReleaseIntArrayElements(env, arr, carr, 0);
 return sum1;

在範例程式碼1中,使用GetIntArrayRegion拷貝數組內容到buf中,這裡沒有做越界異常檢測,因為知道數組有10個,參數3為待拷貝數組的起始位置,參數4為拷貝元素的個數。

JNI支援SetIntArrayRegion允許重新設定數組一個地區的值,其他基本類型(boolean,short, 和float)也有對應的支援。

範例程式碼2示範通過Get/Release<Type>ArrayElemetns返回Java數組的一個拷貝(實現優良的VM,會返回指向Java數組的一個直接的指標,並標記該記憶體地區,不允許被GC)。

 

作者:tangcheng_ok

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.