Android JNI 指標數值轉換

來源:互聯網
上載者:User

JNI通過JNIEnv提供的操作Java數組的功能。它提供了兩個函數:一個是操作java的簡單型數組的,另一個是操作物件類型數組的。

因為速度的原因,簡單類型的數組作為指向本地類型的指標暴露給本地代碼。因此,它們能作為常規的數組存取。這個指標是指向實際的Java數組或者Java數組的拷貝的指標。另外,數組的布置保證匹配本地類型。

為了存取Java簡單類型的數組,你就要要使用GetXXXArrayElements函數(見表A),XXX代表了數組的類型。這個函數把Java數組看成參數,返回一個指向對應的本地類型的數組的指標。

表A

函數 Java 數群組類型
本地類型
GetBooleanArrayElements jbooleanArray
jboolean
GetByteArrayElements jbyteArray
jbyte
GetCharArrayElements jcharArray
jchar
GetShortArrayElements jshortArray
jshort
GetIntArrayElements jintArray
jint
GetLongArrayElements jlongArray
jlong
GetFloatArrayElements jfloatArray
jfloat
GetDoubleArrayElements jdoubleArray
jdouble
JNI數組存取函數

當你對數組的存取完成後,要確保調用相應的ReleaseXXXArrayElements函數,參數是對應Java數組和GetXXXArrayElements返回的指標。如果必要的話,這個釋放函數會複製你做的任何變化(這樣它們就反射到java數組),然後釋放所有相關的資源。

為了使用java對象的數組,你必須使用GetObjectArrayElement函數和SetObjectArrayElement函數,分別去get,set數組的元素。GetArrayLength函數會返回數組的長度。

 

下面通過一個實際的例子,示範一下在JAVA中傳遞基本類型的數組與物件類型的數組,然後在C++中進行相應的處理。

數組傳遞: 

 

JAVA中的代碼:

 

 package com.cjz.ibm;

public class CopyArray {
 static int totalsum = 0;
 static int a[] = new int[] { 1, 2, 3, 4, 5 };
 static String str[] = new String[] { "we", "are", "friends" };
 static {

  System.loadLibrary("CopyArray");

 }

 private native int sum(int[] num);

 private native int sum(String[] str);

 public static void main(String[] args) {

  CopyArray cp = new CopyArray();

  cp.sum(a);
  cp.sum(str);

 }

}

 

在這個簡單的java程式中,我們定義了兩種類型的數組,一種是整形數組,屬於基礎資料型別 (Elementary Data Type)的數組,另一種是字串類型的數組,屬於對象數組。然後把這兩種類型數組分別作為參數傳遞到本地方法sum中去。其中sum函數具有相同的函數名和傳回值類型,區別它們的是參數類型,這樣,就涉及到方法簽名的問題,方法簽名是參數的類型+方法的傳回值類型。可知,它們的方法簽名是不相同的,所以為兩個不同的方法。

經過編譯,產生C++的標頭檔,這個過程可以參考http://blog.csdn.net/chenjin_zhong/archive/2010/09/08/5870305.aspx  

 

 

C++代碼:

 

#include <iostream.h>
#include <string.h>
#include "com_cjz_ibm_CopyArray.h"
JNIEXPORT jint JNICALL Java_com_cjz_ibm_CopyArray_sum___3I
(JNIEnv* env, jobject obj, jintArray array1){
//傳入的參數是整形數組

jint* arr;//定義一個整形指標
int sum=0;
//對於整形數組的處理,主要有GetIntArrayElements與GetIntArrayRegion
//第一種方法
arr=env->GetIntArrayElements(array1,NULL);//得到一個指向未經處理資料類型內容的指標
jint length=env->GetArrayLength(array1);//得到數組的長度

int i=0;
for(i=0;i<length;i++){

 cout<<"arr["<<i<<"]="<<arr[i]<<endl;
 sum+=arr[i];
}

//第二種方法
jint buf[]={0,0,0,0,0};//定義一個jint類型的buffer把原始的數組copy到這個buf中去
env->GetIntArrayRegion(array1,0,length,buf);

for(i=0;i<length;i++){

 cout<<"buf["<<i<<"]="<<buf[i]<<endl;
 sum+=buf[i];
}

//返回一個jint類型的數組

//可以先往一個數組中輸入值,然後把這個數組copy到jintArray中
jintArray iarr =env->NewIntArray(length);//建立一個jintArray
env->SetIntArrayRegion(iarr, 0, length, buf);//將buf中的值複製到jintArray中去,數組copy

//列印新的數組值
jint* arr2;
arr2=env->GetIntArrayElements(iarr,NULL);
for(i=0;i<env->GetArrayLength(iarr);i++){

   cout<<"arr2["<<i<<"]="<<arr2[i]<<endl;

}

 

return sum;

}

JNIEXPORT jint JNICALL Java_com_cjz_ibm_CopyArray_sum___3Ljava_lang_String_2
(JNIEnv* env, jobject obj, jobjectArray array2){
//在java中,String[]類型是對象,所以對應C++中的數組為jobjectArray

//把jobjectArray數組中的值取出來

 int size=env->GetArrayLength(array2);//得到數組的長度值
 int i=0;
 cout<<"輸出原始的數組值:"<<endl;
 for(i=0;i<size;i++){
 jstring obja=(jstring)env->GetObjectArrayElement(array2,i);
 const char* chars=env->GetStringUTFChars(obja,NULL);//將jstring類型轉換成char類型輸出
 cout<<chars<<endl;
 
 }

//複製數組到新的數組中

cout<<"複製之後的數組為:"<<endl;

jclass objClass = env->FindClass("java/lang/String");//定義數組中元素類型

jobjectArray texts= env->NewObjectArray(size, objClass, 0);//建立一個數群組類型為String類型

   jstring jstr;

       for(i=0;i<size;i++)

        {
        
         jstr=(jstring)env->GetObjectArrayElement(array2,i);//把array2中的元素取出來

          env->SetObjectArrayElement(texts, i, jstr);//放入到texts數組中去,必須放入jstring

       }

 for(i=0;i<size;i++){

 jstring str1=(jstring)env->GetObjectArrayElement(texts,i);//列印出新複製的數組值
 const char* chars1=env->GetStringUTFChars(str1,NULL);
 cout<<chars1<<endl;
 
 }
     
return 0;

 

}

 

 

 

在C++代碼中,int類型的數組對應JNI中的jintArray,而字串類型的數組對應jobjectArray.

首先分析一下代碼:

GetIntArrayElements(<ArrayType>array,jboolean *isCopy):第一個參數傳遞的是數組名,第二個參數傳遞的是否返回一個複製的數組。傳回值:返回一個指向數組的指標。

 

GetIntArrayRegion(<ArrayType>array,jsize start,jsize len,<NativeType> *buf)

array:a reference to an array whose elements are to be copied.

start:the starting index of the array elements to be copied.

len: the number of elements to be copied.

buf: the destination buffer.

功能:把jintArray中的元素複製到buffer中。

 

 

SetIntArrayRegion(<ArrayType>array,jsize start,jsize len,<NativeType>*buf)

array:a reference to a primitive array to which the elements to be copied.

start:the starting index in the primitive array.

len:the number of elements to be copied.

buf:the source buffer.

 

功能:把buf中的元素copy到jintArray中去。

 

可見,SetIntArrayRegion與GetIntArrayRegion是設定jintArray數組與取出jintArray數組中的值。

 

 

NewIntArray(jsize length)

length:the number of elements in the array to be created.

功能:構造一個數組對象

傳回值:返回一個jintArray類型。

 

GetArrayLength(<ArrayType>array)

傳回值:返回jintArray的長度。

 

 

由於在C++中,jintArray不能用下標直接存取,所以用到JNI中提供的介面函數進行操作。

 

 

GetObjectArrayElement(jobjectArray array,jsize index)

array: a reference to the java.lang.Object array from which the element will be accessed.

index: the array index

 

功能:返回對應索引值的object.返回的是一個數組元素的值。

 

SetObjectArrayElement(jobjectArray array,jsize index,jobject value)

array: a reference to an array whose element will be accessed.

index: index of the array element to be accessed.

value: the new value of the array element.

 

功能:用來設定對應索引元素的值。

 

 

因此,對於基本類型的數組,我們可以用Get<Type>ArrayElements和Get<Type>ArrayRegion來操作。

而Set<Type>ArrayRegion傳遞一個預先設定好的buf來返回一個j<Type>Array.而對於jobjectArray,可以用SetObjectArrayElement與GetObjectArrayElement來設定元素的值與返回元素的值。

 

對於數組的操作就介紹到這了。

 

異常處理:

下面看一個簡單的例子:

 

JAVA代碼:

ackage com.ibm.cjz;

public class Exception1 {

 private native void doit();

 private void callback() {

  int a[] = new int[3];
  System.out.println(a[5]);// 數組越界,在C++中會發生異常,然後C++中把這個異常傳遞給java

 }

 public static void main(String[] args) {

  try {
   Exception1 ex = new Exception1();

   ex.doit();
  } catch (Exception ex) {

   System.out.println(ex);

  }

 }

 static {

  System.loadLibrary("Exception");

 }
}

 

在這個JAVA代碼中,定義了一個整形數組,然後在callback()方法中調用這個數組,可以看到數組越界了,下面示範在C++中如何捕獲這個異常。

 

C++代碼:

#include "com_ibm_cjz_Exception1.h"
#include <iostream.h>
#include <string.h>
JNIEXPORT void JNICALL Java_com_ibm_cjz_Exception1_doit
(JNIEnv* env, jobject obj){

jclass cls=env->GetObjectClass(obj);
jmethodID mid=env->GetMethodID(cls,"callback","()V");
env->CallVoidMethod(obj,mid);
//調用callback方法,擷取異常資訊

jthrowable excp=0;
const char* str;
excp=env->ExceptionOccurred();//得到異常對象
if(excp){

    jclass cls=env->GetObjectClass(excp);
    //env->ExceptionClear();
    //env->ExceptionDescribe();
    jmethodID mid=env->GetMethodID(cls,"toString","()Ljava/lang/String;");//調用String中的toString方法
    jstring msg=(jstring)env->CallObjectMethod(excp,mid);
    str=env->GetStringUTFChars(msg,NULL);
    cout<<"In C:"<<str<<endl;
    env->ExceptionClear();//把這個異常清除掉,使之不能傳遞到java

 

}

 

jclass errclass;
errclass=env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
env->ThrowNew(errclass, "thrown from C++ code");//向java中拋出異常

 

 

}

 

 

 

jthrowable ExceptionOccurred(JNIEnv *env);

傳回值:返回一個異常對象。

 

void ExceptionClear(JNIEnv *env);

功能:清除該異常對象,只在本線程中傳遞。

 

 

jint ThrowNew(JNIEnv *env, jclass clazz,
const char *message);

功能:拋出一個指定的異常對象和異常資訊。

 

列印結果:

In C:java.lang.ArrayIndexOutOfBoundsException: 5
java.lang.ArrayIndexOutOfBoundsException: thrown from C++ code

 

第一行是C++中列印的資訊,第二行是從C++中拋出的異常。

如果把 env->ExceptionClear();//把這個異常清除掉,使之不能傳遞到java

jclass errclass;
errclass=env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
env->ThrowNew(errclass, "thrown from C++ code");//向java中拋出異常

都注釋掉,也會向JAVA中拋出異常。這時就沒有清除掉異常了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.